<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.9.0">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
    <title>
        Java 面试题系列篇-Spring 框架 |
        
        Darklovy</title>
    <meta name="description" content>
    <meta name="keywords" content>
    <meta name="HandheldFriendly" content="True">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="shortcut icon" href="/">
    <link rel="alternate" href="/atom.xml" title="Darklovy">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="description" content="Spring 框架【Spring】使用Spring框架的好处是什么？轻量：Spring 是轻量的，基本的版本大约2MB 控制反转：Spring通过控制反转实现了松散耦合，对象们给出它们的依赖，而不是创建或查找依赖的对象们 面向切面的编程(AOP)：Spring支持面向切面的编程，并且把应用业务逻辑和系统服务分开 容器：Spring 包含并管理应用中对象的生命周期和配置 MVC框架：Spring的W">
<meta name="keywords" content="Java">
<meta property="og:type" content="article">
<meta property="og:title" content="Java 面试题系列篇-Spring 框架">
<meta property="og:url" content="https://www.ttxxly.top/2018/10/20/Java-面试题系列篇-Spring-框架/index.html">
<meta property="og:site_name" content="Darklovy">
<meta property="og:description" content="Spring 框架【Spring】使用Spring框架的好处是什么？轻量：Spring 是轻量的，基本的版本大约2MB 控制反转：Spring通过控制反转实现了松散耦合，对象们给出它们的依赖，而不是创建或查找依赖的对象们 面向切面的编程(AOP)：Spring支持面向切面的编程，并且把应用业务逻辑和系统服务分开 容器：Spring 包含并管理应用中对象的生命周期和配置 MVC框架：Spring的W">
<meta property="og:locale" content="en">
<meta property="og:updated_time" content="2018-12-25T07:27:58.298Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java 面试题系列篇-Spring 框架">
<meta name="twitter:description" content="Spring 框架【Spring】使用Spring框架的好处是什么？轻量：Spring 是轻量的，基本的版本大约2MB 控制反转：Spring通过控制反转实现了松散耦合，对象们给出它们的依赖，而不是创建或查找依赖的对象们 面向切面的编程(AOP)：Spring支持面向切面的编程，并且把应用业务逻辑和系统服务分开 容器：Spring 包含并管理应用中对象的生命周期和配置 MVC框架：Spring的W">

    <link href="https://fonts.googleapis.com/css?family=Inconsolata|Titillium+Web" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
    <link href="//cdn.bootcss.com/node-waves/0.7.5/waves.min.css" rel="stylesheet">
    <link rel="stylesheet" href="/style.css">
    <script>
        function setLoadingBarProgress(num) {
            document.getElementById('loading-bar').style.width = num + "%";
        }
    </script>
</head>
</html>
<body>
  <div id="loading-bar-wrapper">
  <div id="loading-bar"></div>
</div>


  <script>setLoadingBarProgress(20)</script> 
  <header class="l_header">
	<div class='wrapper'>
		<div class="nav-main container container--flex">
			<a class="logo flat-box" href='/' >
				Darklovy
			</a>
			<div class='menu'>
				<ul class='h-list'>
					
						<li>
							<a class='flat-box nav-Home' href='/'>
								首页
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-archives' href='/archives'>
								归档
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-categories' href='/categories'>
								分类
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-tags' href='/tags'>
								标签
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-algorithm' href='https://book.algorithm.ttxxly.top/'>
								算法
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-python' href='https://book.python.ttxxly.top/'>
								python
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-about' href='/about'>
								关于
							</a>
						</li>
					
				</ul>
				<div class='underline'></div>
			</div>
			
				<div class="m_search">
					<form name="searchform" class="form u-search-form">
						<input type="text" class="input u-search-input" placeholder="Search" />
						<span class="icon icon-search"></span>
					</form>
				</div>
			
			<ul class='switcher h-list'>
				
					<li class='s-search'><a href='javascript:void(0)'><span class="icon icon-search flat-box"></span></a></li>
				
				<li class='s-menu'><a href='javascript:void(0)'><span class="icon icon-menu flat-box"></span></a></li>
			</ul>
		</div>
		
		<div class='nav-sub container container--flex'>
			<a class="logo" class="flat-box" href='javascript:void(0)'>
				Word of Forks
			</a>

			<ul class='switcher h-list'>
				<li class='s-comment'><a href='javascript:void(0)'><span class="icon icon-chat_bubble_outline flat-box"></span></a></li>
				<li class='s-top'><a href='javascript:void(0)'><span class="icon icon-arrow_upward flat-box"></span></a></li>
				<li class='s-toc'><a href='javascript:void(0)'><span class="icon icon-format_list_numbered flat-box"></span></a></li>
			</ul>
		</div>
	</div>
</header>
<aside class="menu-phone">
	<nav>
		
			<a href="/" class="nav-Home nav">
				首页
			</a>
		
			<a href="/archives" class="nav-archives nav">
				归档
			</a>
		
			<a href="/categories" class="nav-categories nav">
				分类
			</a>
		
			<a href="/tags" class="nav-tags nav">
				标签
			</a>
		
			<a href="https://book.algorithm.ttxxly.top/" class="nav-algorithm nav">
				算法
			</a>
		
			<a href="https://book.python.ttxxly.top/" class="nav-python nav">
				python
			</a>
		
			<a href="/about" class="nav-about nav">
				关于
			</a>
		
	</nav>
</aside>

    <script>setLoadingBarProgress(40);</script>
  <div class="l_body">
    <div class='container clearfix'>
      <div class='l_main'>
        <article id="post-Java-面试题系列篇-Spring-框架"
  class="post white-box article-type-post"
  itemscope itemprop="blogPost">
	<section class='meta'>
	<h2 class="title">
  	<a href="/2018/10/20/Java-面试题系列篇-Spring-框架/">
    	Java 面试题系列篇-Spring 框架
    </a>
  </h2>
	<time>
	  Oct 20, 2018
	</time>
	
	</section>
	
		<section class="toc-wrapper"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring-框架"><span class="toc-number">1.</span> <span class="toc-text">Spring 框架</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】使用Spring框架的好处是什么？"><span class="toc-number">1.1.</span> <span class="toc-text">【Spring】使用Spring框架的好处是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是IoC和DI？DI是如何实现的？"><span class="toc-number">1.2.</span> <span class="toc-text">什么是IoC和DI？DI是如何实现的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring中Bean的作用域有哪些？"><span class="toc-number">1.3.</span> <span class="toc-text">Spring中Bean的作用域有哪些？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#解释一下什么叫AOP（面向切面编程）？"><span class="toc-number">1.4.</span> <span class="toc-text">解释一下什么叫AOP（面向切面编程）？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#你是如何理解”横切关注”这个概念的？"><span class="toc-number">1.5.</span> <span class="toc-text">你是如何理解”横切关注”这个概念的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？"><span class="toc-number">1.6.</span> <span class="toc-text">你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring中自动装配的方式有哪些？"><span class="toc-number">1.7.</span> <span class="toc-text">Spring中自动装配的方式有哪些？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring中如何使用注解来配置Bean？有哪些相关的注解？"><span class="toc-number">1.8.</span> <span class="toc-text">Spring中如何使用注解来配置Bean？有哪些相关的注解？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？"><span class="toc-number">1.9.</span> <span class="toc-text">Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何在Web项目中配置Spring的IoC容器？"><span class="toc-number">1.10.</span> <span class="toc-text">如何在Web项目中配置Spring的IoC容器？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何在Spring-IoC容器中配置数据源？"><span class="toc-number">1.11.</span> <span class="toc-text">如何在Spring IoC容器中配置数据源？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何配置配置事务增强？"><span class="toc-number">1.12.</span> <span class="toc-text">如何配置配置事务增强？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？"><span class="toc-number">1.13.</span> <span class="toc-text">选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring-IoC容器配置Bean的方式？"><span class="toc-number">1.14.</span> <span class="toc-text">Spring IoC容器配置Bean的方式？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#阐述Spring框架中Bean的生命周期？"><span class="toc-number">1.15.</span> <span class="toc-text">阐述Spring框架中Bean的生命周期？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#依赖注入时如何注入集合属性？"><span class="toc-number">1.16.</span> <span class="toc-text">依赖注入时如何注入集合属性？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring中的自动装配有哪些限制？"><span class="toc-number">1.17.</span> <span class="toc-text">Spring中的自动装配有哪些限制？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#在Web项目中如何获得Spring的IoC容器？"><span class="toc-number">1.18.</span> <span class="toc-text">在Web项目中如何获得Spring的IoC容器？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Spring由哪些模块组成？"><span class="toc-number">1.19.</span> <span class="toc-text">Spring由哪些模块组成？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是Spring-IOC-容器？"><span class="toc-number">1.20.</span> <span class="toc-text">【Spring】什么是Spring IOC 容器？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】IOC的优点是什么？"><span class="toc-number">1.21.</span> <span class="toc-text">【Spring】IOC的优点是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】ApplicationContext通常的实现是什么？"><span class="toc-number">1.22.</span> <span class="toc-text">【Spring】ApplicationContext通常的实现是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Bean-工厂和-Application-contexts-有什么区别？"><span class="toc-number">1.23.</span> <span class="toc-text">【Spring】Bean 工厂和 Application contexts  有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是Spring的依赖注入？"><span class="toc-number">1.24.</span> <span class="toc-text">【Spring】什么是Spring的依赖注入？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】有哪些不同类型的IOC（依赖注入）方式？"><span class="toc-number">1.25.</span> <span class="toc-text">【Spring】有哪些不同类型的IOC（依赖注入）方式？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】哪种依赖注入方式你建议使用，构造器注入，还是-Setter方法注入？"><span class="toc-number">1.26.</span> <span class="toc-text">【Spring】哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是Spring-beans？"><span class="toc-number">1.27.</span> <span class="toc-text">【Spring】什么是Spring beans？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】一个-Spring-Bean-定义-包含什么？"><span class="toc-number">1.28.</span> <span class="toc-text">【Spring】一个 Spring Bean 定义 包含什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】如何给Spring-容器提供配置元数据？"><span class="toc-number">1.29.</span> <span class="toc-text">【Spring】如何给Spring 容器提供配置元数据？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】解释Spring支持的几种bean的作用域"><span class="toc-number">1.30.</span> <span class="toc-text">【Spring】解释Spring支持的几种bean的作用域</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Spring框架中的单例bean是线程安全的吗？"><span class="toc-number">1.31.</span> <span class="toc-text">【Spring】Spring框架中的单例bean是线程安全的吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】解释Spring框架中bean的生命周期"><span class="toc-number">1.32.</span> <span class="toc-text">【Spring】解释Spring框架中bean的生命周期</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】哪些是重要的bean生命周期方法？-你能重载它们吗？"><span class="toc-number">1.33.</span> <span class="toc-text">【Spring】哪些是重要的bean生命周期方法？ 你能重载它们吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】在-Spring中如何注入一个java集合？"><span class="toc-number">1.34.</span> <span class="toc-text">【Spring】在 Spring中如何注入一个java集合？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是bean装配？"><span class="toc-number">1.35.</span> <span class="toc-text">【Spring】什么是bean装配？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是bean的自动装配？"><span class="toc-number">1.36.</span> <span class="toc-text">【Spring】什么是bean的自动装配？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】解释不同方式的自动装配"><span class="toc-number">1.37.</span> <span class="toc-text">【Spring】解释不同方式的自动装配</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】自动装配有哪些局限性？"><span class="toc-number">1.38.</span> <span class="toc-text">【Spring】自动装配有哪些局限性？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】你可以在Spring中注入一个null-和一个空字符串吗？"><span class="toc-number">1.39.</span> <span class="toc-text">【Spring】你可以在Spring中注入一个null 和一个空字符串吗？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是基于Java的Spring注解配置-给一些注解的例子"><span class="toc-number">1.40.</span> <span class="toc-text">【Spring】什么是基于Java的Spring注解配置? 给一些注解的例子</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是基于注解的容器配置？"><span class="toc-number">1.41.</span> <span class="toc-text">【Spring】什么是基于注解的容器配置？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】怎样开启注解装配？"><span class="toc-number">1.42.</span> <span class="toc-text">【Spring】怎样开启注解装配？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-Required-注解"><span class="toc-number">1.43.</span> <span class="toc-text">【Spring】@Required  注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-Autowired-注解"><span class="toc-number">1.44.</span> <span class="toc-text">【Spring】@Autowired 注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-Qualifier-注解"><span class="toc-number">1.45.</span> <span class="toc-text">【Spring】@Qualifier 注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】在Spring框架中如何更有效地使用JDBC？"><span class="toc-number">1.46.</span> <span class="toc-text">【Spring】在Spring框架中如何更有效地使用JDBC？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-JdbcTemplate"><span class="toc-number">1.47.</span> <span class="toc-text">【Spring】 JdbcTemplate</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Spring对DAO的支持"><span class="toc-number">1.48.</span> <span class="toc-text">【Spring】Spring对DAO的支持</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】使用Spring通过什么方式访问Hibernate？"><span class="toc-number">1.49.</span> <span class="toc-text">【Spring】使用Spring通过什么方式访问Hibernate？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Spring支持的ORM"><span class="toc-number">1.50.</span> <span class="toc-text">【Spring】Spring支持的ORM</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？"><span class="toc-number">1.51.</span> <span class="toc-text">【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Spring支持的事务管理类型"><span class="toc-number">1.52.</span> <span class="toc-text">【Spring】Spring支持的事务管理类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Spring框架的事务管理有哪些优点？"><span class="toc-number">1.53.</span> <span class="toc-text">【Spring】Spring框架的事务管理有哪些优点？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】你更倾向用那种事务管理类型？"><span class="toc-number">1.54.</span> <span class="toc-text">【Spring】你更倾向用那种事务管理类型？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-解释AOP"><span class="toc-number">1.55.</span> <span class="toc-text">【Spring】 解释AOP</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】Aspect-切面"><span class="toc-number">1.56.</span> <span class="toc-text">【Spring】Aspect 切面</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】在Spring-AOP-中，关注点和横切关注的区别是什么？"><span class="toc-number">1.57.</span> <span class="toc-text">【Spring】在Spring AOP 中，关注点和横切关注的区别是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】连接点"><span class="toc-number">1.58.</span> <span class="toc-text">【Spring】连接点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】通知"><span class="toc-number">1.59.</span> <span class="toc-text">【Spring】通知</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】切点"><span class="toc-number">1.60.</span> <span class="toc-text">【Spring】切点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是引入？"><span class="toc-number">1.61.</span> <span class="toc-text">【Spring】什么是引入？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是目标对象？"><span class="toc-number">1.62.</span> <span class="toc-text">【Spring】什么是目标对象？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是代理？"><span class="toc-number">1.63.</span> <span class="toc-text">【Spring】什么是代理？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】有几种不同类型的自动代理？"><span class="toc-number">1.64.</span> <span class="toc-text">【Spring】有几种不同类型的自动代理？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是织入。什么是织入应用的不同点？"><span class="toc-number">1.65.</span> <span class="toc-text">【Spring】什么是织入。什么是织入应用的不同点？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】解释基于XML-Schema方式的切面实现"><span class="toc-number">1.66.</span> <span class="toc-text">【Spring】解释基于XML Schema方式的切面实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】解释基于注解的切面实现"><span class="toc-number">1.67.</span> <span class="toc-text">【Spring】解释基于注解的切面实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是Spring的MVC框架？"><span class="toc-number">1.68.</span> <span class="toc-text">【Spring】什么是Spring的MVC框架？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】DispatcherServlet"><span class="toc-number">1.69.</span> <span class="toc-text">【Spring】DispatcherServlet</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】WebApplicationContext"><span class="toc-number">1.70.</span> <span class="toc-text">【Spring】WebApplicationContext</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】什么是Spring-MVC框架的控制器？"><span class="toc-number">1.71.</span> <span class="toc-text">【Spring】什么是Spring MVC框架的控制器？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-Controller-注解"><span class="toc-number">1.72.</span> <span class="toc-text">【Spring】@Controller 注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#【Spring】-RequestMapping-注解"><span class="toc-number">1.73.</span> <span class="toc-text">【Spring】@RequestMapping 注解</span></a></li></ol></li></ol></section>
	
	<section class="article typo">
  	<div class="article-entry" itemprop="articleBody">
    	<h2 id="Spring-框架"><a href="#Spring-框架" class="headerlink" title="Spring 框架"></a>Spring 框架</h2><h3 id="【Spring】使用Spring框架的好处是什么？"><a href="#【Spring】使用Spring框架的好处是什么？" class="headerlink" title="【Spring】使用Spring框架的好处是什么？"></a>【Spring】使用Spring框架的好处是什么？</h3><p>轻量：Spring 是轻量的，基本的版本大约2MB</p>
<p>控制反转：Spring通过控制反转实现了松散耦合，对象们给出它们的依赖，而不是创建或查找依赖的对象们</p>
<p>面向切面的编程(AOP)：Spring支持面向切面的编程，并且把应用业务逻辑和系统服务分开</p>
<p>容器：Spring 包含并管理应用中对象的生命周期和配置</p>
<p>MVC框架：Spring的WEB框架是个精心设计的框架，是Web框架的一个很好的替代品</p>
<p>事务管理：Spring 提供一个持续的事务管理接口，可以扩展到上至本地事务下至全局事务（JTA）</p>
<p>异常处理：Spring 提供方便的API把具体技术相关的异常（比如由JDBC，Hibernate or JDO抛出的）转化为一致的unchecked 异常</p>
<h3 id="什么是IoC和DI？DI是如何实现的？"><a href="#什么是IoC和DI？DI是如何实现的？" class="headerlink" title="什么是IoC和DI？DI是如何实现的？"></a>什么是IoC和DI？DI是如何实现的？</h3><p>答：IoC叫控制反转，是Inversion of Control的缩写，DI（Dependency Injection）叫依赖注入，是对IoC更简单的诠释。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器，通过容器来实现对象组件的装配和管理。所谓的”控制反转”就是对组件对象控制权的转移，从程序代码本身转移到了外部容器，由容器来创建对象并管理对象之间的依赖关系。IoC体现了好莱坞原则 - “Don’t call me, we will call you”。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责，查找资源的逻辑应该从应用组件的代码中抽取出来，交给容器来完成。DI是对IoC更准确的描述，即组件之间的依赖关系由容器在运行期决定，形象的来说，即由容器动态的将某种依赖关系注入到组件之中。</p>
<p>举个例子：一个类A需要用到接口B中的方法，那么就需要为类A和接口B建立关联或依赖关系，最原始的方法是在类A中创建一个接口B的实现类C的实例，但这种方法需要开发人员自行维护二者的依赖关系，也就是说当依赖关系发生变动的时候需要修改代码并重新构建整个系统。如果通过一个容器来管理这些对象以及对象的依赖关系，则只需要在类A中定义好用于关联接口B的方法（构造器或setter方法），将类A和接口B的实现类C放入容器中，通过对容器的配置来实现二者的关联。</p>
<p>依赖注入可以通过setter方法注入（设值注入）、构造器注入和接口注入三种方式来实现，Spring支持setter注入和构造器注入，通常使用构造器注入来注入必须的依赖关系，对于可选的依赖关系，则setter注入是更好的选择，setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。</p>
<h3 id="Spring中Bean的作用域有哪些？"><a href="#Spring中Bean的作用域有哪些？" class="headerlink" title="Spring中Bean的作用域有哪些？"></a>Spring中Bean的作用域有哪些？</h3><p>答：在Spring的早期版本中，仅有两个作用域：singleton和prototype，前者表示Bean以单例的方式存在；后者表示每次从容器中调用Bean时，都会返回一个新的实例，prototype通常翻译为原型。</p>
<p>补充：设计模式中的创建型模式中也有一个原型模式，原型模式也是一个常用的模式，例如做一个室内设计软件，所有的素材都在工具箱中，而每次从工具箱中取出的都是素材对象的一个原型，可以通过对象克隆来实现原型模式。</p>
<p>Spring 2.x中针对WebApplicationContext新增了3个作用域，分别是：request（每次HTTP请求都会创建一个新的Bean）、session（同一个HttpSession共享同一个Bean，不同的HttpSession使用不同的Bean）和globalSession（同一个全局Session共享一个Bean）。</p>
<p>说明：单例模式和原型模式都是重要的设计模式。一般情况下，无状态或状态不可变的类适合使用单例模式。在传统开发中，由于DAO持有Connection这个非线程安全对象因而没有使用单例模式；但在Spring环境下，所有DAO类对可以采用单例模式，因为Spring利用AOP和Java API中的ThreadLocal对非线程安全的对象进行了特殊处理。</p>
<p>ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。ThreadLocal，顾名思义是线程的一个本地化对象，当工作于多线程中的对象使用ThreadLocal维护变量时，ThreadLocal为每个使用该变量的线程分配一个独立的变量副本，所以每一个线程都可以独立的改变自己的副本，而不影响其他线程所对应的副本。从线程的角度看，这个变量就像是线程的本地变量。</p>
<p>ThreadLocal类非常简单好用，只有四个方法，能用上的也就是下面三个方法： </p>
<ul>
<li>void set(T value)：设置当前线程的线程局部变量的值。 </li>
<li>T get()：获得当前线程所对应的线程局部变量的值。 </li>
<li>void remove()：删除当前线程中线程局部变量的值。</li>
</ul>
<p>ThreadLocal是如何做到为每一个线程维护一份独立的变量副本的呢？在ThreadLocal类中有一个Map，键为线程对象，值是其线程对应的变量的副本，自己要模拟实现一个ThreadLocal类其实并不困难，代码如下所示：</p>
<p>import java.util.Collections;</p>
<p>import java.util.HashMap;</p>
<p>import java.util.Map;</p>
<p>public class MyThreadLocal<t> {</t></p>
<p>​    private Map&lt;Thread, T&gt; map = Collections.synchronizedMap(new HashMap&lt;Thread, T&gt;());</p>
<p>​    public void set(T newValue) {</p>
<p>​        map.put(Thread.currentThread(), newValue);</p>
<p>​    }</p>
<p>​    public T get() {</p>
<p>​        return map.get(Thread.currentThread());</p>
<p>​    }</p>
<p>​    public void remove() {</p>
<p>​        map.remove(Thread.currentThread());</p>
<p>​    }</p>
<p>}</p>
<h3 id="解释一下什么叫AOP（面向切面编程）？"><a href="#解释一下什么叫AOP（面向切面编程）？" class="headerlink" title="解释一下什么叫AOP（面向切面编程）？"></a>解释一下什么叫AOP（面向切面编程）？</h3><p>答：AOP（Aspect-Oriented Programming）指一种程序设计范型，该范型以一种称为切面（aspect）的语言构造为基础，切面是一种新的模块化机制，用来描述分散在对象、类或方法中的横切关注点（crosscutting concern）。</p>
<h3 id="你是如何理解”横切关注”这个概念的？"><a href="#你是如何理解”横切关注”这个概念的？" class="headerlink" title="你是如何理解”横切关注”这个概念的？"></a>你是如何理解”横切关注”这个概念的？</h3><p>答：”横切关注”是会影响到整个应用程序的关注功能，它跟正常的业务逻辑是正交的，没有必然的联系，但是几乎所有的业务逻辑都会涉及到这些关注功能。通常，事务、日志、安全性等关注就是应用中的横切关注功能。</p>
<h3 id="你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？"><a href="#你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？" class="headerlink" title="你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？"></a>你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？</h3><p>答：<br>a. 连接点（Joinpoint）：程序执行的某个特定位置（如：某个方法调用前、调用后，方法抛出异常后）。一个类或一段程序代码拥有一些具有边界性质的特定点，这些代码中的特定点就是连接点。Spring仅支持方法的连接点。<br>b. 切点（Pointcut）：如果连接点相当于数据中的记录，那么切点相当于查询条件，一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件，找到对应的连接点。<br>c. 增强（Advice）：增强是织入到目标类连接点上的一段程序代码。Spring提供的增强接口都是带方位名的，如：BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。很多资料上将增强译为“通知”，这明显是个词不达意的翻译，让很多程序员困惑了许久。</p>
<p>说明： Advice在国内的很多书面资料中都被翻译成”通知”，但是很显然这个翻译无法表达其本质，有少量的读物上将这个词翻译为”增强”，这个翻译是对Advice较为准确的诠释，我们通过AOP将横切关注功能加到原有的业务逻辑上，这就是对原有业务逻辑的一种增强，这种增强可以是前置增强、后置增强、返回后增强、抛异常时增强和包围型增强。</p>
<p>d. 引介（Introduction）：引介是一种特殊的增强，它为类添加一些属性和方法。这样，即使一个业务类原本没有实现某个接口，通过引介功能，可以动态的未该业务类添加接口的实现逻辑，让业务类成为这个接口的实现类。<br>e. 织入（Weaving）：织入是将增强添加到目标类具体连接点上的过程，AOP有三种织入方式：①编译期织入：需要特殊的Java编译期（例如AspectJ的ajc）；②装载期织入：要求使用特殊的类加载器，在装载类的时候对类进行增强；③运行时织入：在运行时为目标类生成代理实现增强。Spring采用了动态代理的方式实现了运行时织入，而AspectJ采用了编译期织入和装载期织入的方式。<br>f. 切面（Aspect）：切面是由切点和增强（引介）组成的，它包括了对横切关注功能的定义，也包括了对连接点的定义。</p>
<p>补充：代理模式是GoF提出的23种设计模式中最为经典的模式之一，代理模式是对象的结构模式，它给某一个对象提供一个代理对象，并由代理对象控制对原对象的引用。简单的说，代理对象可以完成比原对象更多的职责，当需要为原对象添加横切关注功能时，就可以使用原对象的代理对象。我们在打开Office系列的Word文档时，如果文档中有插图，当文档刚加载时，文档中的插图都只是一个虚框占位符，等用户真正翻到某页要查看该图片时，才会真正加载这张图，这其实就是对代理模式的使用，代替真正图片的虚框就是一个虚拟代理；Hibernate的load方法也是返回一个虚拟代理对象，等用户真正需要访问对象的属性时，才向数据库发出SQL语句获得真实对象。</p>
<p>下面用一个找枪手代考的例子演示代理模式的使用：</p>
<p>/**</p>
<ul>
<li>参考人员接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface Candidate {</p>
<p>​    /**</p>
<p>​     * 答题</p>
<p>​     */</p>
<p>​    public void answerTheQuestions();</p>
<p>}</p>
<p>/**</p>
<ul>
<li>懒学生</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public class LazyStudent implements Candidate {</p>
<p>​    private String name;        // 姓名</p>
<p>​    public LazyStudent(String name) {</p>
<p>​        this.name = name;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void answerTheQuestions() {</p>
<p>​        // 懒学生只能写出自己的名字不会答题</p>
<p>​        System.out.println(“姓名: “ + name);</p>
<p>​    }</p>
<p>}</p>
<p>/**</p>
<ul>
<li>枪手</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public class Gunman implements Candidate {</p>
<p>​    private Candidate target;   // 被代理对象</p>
<p>​    public Gunman(Candidate target) {</p>
<p>​        this.target = target;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void answerTheQuestions() {</p>
<p>​        // 枪手要写上代考的学生的姓名</p>
<p>​        target.answerTheQuestions();</p>
<p>​        // 枪手要帮助懒学生答题并交卷</p>
<p>​        System.out.println(“奋笔疾书正确答案”);</p>
<p>​        System.out.println(“交卷”);</p>
<p>​    }</p>
<p>}</p>
<p>public class ProxyTest1 {</p>
<p>​    public static void main(String[] args) {</p>
<p>​        Candidate c = new Gunman(new LazyStudent(“王小二”));</p>
<p>​        c.answerTheQuestions();</p>
<p>​    }</p>
<p>}</p>
<p>说明：从JDK 1.3开始，Java提供了动态代理技术，允许开发者在运行时创建接口的代理实例，主要包括Proxy类和InvocationHandler接口。下面的例子使用动态代理为ArrayList编写一个代理，在添加和删除元素时，在控制台打印添加或删除的元素以及ArrayList的大小：</p>
<p>import java.lang.reflect.InvocationHandler;</p>
<p>import java.lang.reflect.Method;</p>
<p>import java.util.List;</p>
<p>public class ListProxy<t> implements InvocationHandler {</t></p>
<p>​    private List<t> target;</t></p>
<p>​    public ListProxy(List<t> target) {</t></p>
<p>​        this.target = target;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public Object invoke(Object proxy, Method method, Object[] args)</p>
<p>​            throws Throwable {</p>
<p>​        Object retVal = null;</p>
<p>​        System.out.println(“[“ + method.getName() + “: “ + args[0] + “]”);</p>
<p>​        retVal = method.invoke(target, args);</p>
<p>​        System.out.println(“[size=” + target.size() + “]”);</p>
<p>​        return retVal;</p>
<p>​    }</p>
<p>}</p>
<p>import java.lang.reflect.Proxy;</p>
<p>import java.util.ArrayList;</p>
<p>import java.util.List;</p>
<p>public class ProxyTest2 {</p>
<p>​    @SuppressWarnings(“unchecked”)</p>
<p>​    public static void main(String[] args) {</p>
<p>​        List<string> list = new ArrayList<string>();</string></string></p>
<p>​        Class&lt;?&gt; clazz = list.getClass();</p>
<p>​        ListProxy<string> myProxy = new ListProxy<string>(list);</string></string></p>
<p>​        List<string> newList = (List<string>) </string></string></p>
<p>​                Proxy.newProxyInstance(clazz.getClassLoader(), </p>
<p>​                clazz.getInterfaces(), myProxy);</p>
<p>​        newList.add(“apple”);</p>
<p>​        newList.add(“banana”);</p>
<p>​        newList.add(“orange”);</p>
<p>​        newList.remove(“banana”);</p>
<p>​    }</p>
<p>}</p>
<p>说明：使用Java的动态代理有一个局限性就是代理的类必须要实现接口，虽然面向接口编程是每个优秀的Java程序都知道的规则，但现实往往不尽如人意，对于没有实现接口的类如何为其生成代理呢？继承！继承是最经典的扩展已有代码能力的手段，虽然继承常常被初学者滥用，但继承也常常被进阶的程序员忽视。CGLib采用非常底层的字节码生成技术，通过为一个类创建子类来生成代理，它弥补了Java动态代理的不足，因此Spring中动态代理和CGLib都是创建代理的重要手段，对于实现了接口的类就用动态代理为其生成代理类，而没有实现接口的类就用CGLib通过继承的方式为其创建代理。</p>
<h3 id="Spring中自动装配的方式有哪些？"><a href="#Spring中自动装配的方式有哪些？" class="headerlink" title="Spring中自动装配的方式有哪些？"></a>Spring中自动装配的方式有哪些？</h3><p> 答： </p>
<ul>
<li>no：不进行自动装配，手动设置Bean的依赖关系。 </li>
<li>byName：根据Bean的名字进行自动装配。 </li>
<li>byType：根据Bean的类型进行自动装配。 </li>
<li>constructor：类似于byType，不过是应用于构造器的参数，如果正好有一个Bean与构造器的参数类型相同则可以自动装配，否则会导致错误。 </li>
<li>autodetect：如果有默认的构造器，则通过constructor的方式进行自动装配，否则使用byType的方式进行自动装配。</li>
</ul>
<p>说明：自动装配没有自定义装配方式那么精确，而且不能自动装配简单属性（基本类型、字符串等），在使用时应注意。</p>
<h3 id="Spring中如何使用注解来配置Bean？有哪些相关的注解？"><a href="#Spring中如何使用注解来配置Bean？有哪些相关的注解？" class="headerlink" title="Spring中如何使用注解来配置Bean？有哪些相关的注解？"></a>Spring中如何使用注解来配置Bean？有哪些相关的注解？</h3><p>答：首先需要在Spring配置文件中增加如下配置：</p>
<p>&lt;context:component-scan base-package=”org.example”/&gt;</p>
<p>然后可以用@Component、@Controller、@Service、@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别，只不过@Controller通常用于控制器，@Service通常用于业务逻辑类，@Repository通常用于仓储类（例如我们的DAO实现类），普通的类用@Component来标注。</p>
<h3 id="Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？"><a href="#Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？" class="headerlink" title="Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？"></a>Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？</h3><p>答：Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理，因为这种方式和应用程序的关联较少，因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理，尽管在灵活性方面它弱于编程式事务管理，因为编程式事务允许你通过代码控制业务。</p>
<p>事务分为全局事务和局部事务。全局事务由应用服务器管理，需要底层服务器JTA支持（如WebLogic、WildFly等）。局部事务和底层采用的持久化方案有关，例如使用JDBC进行持久化时，需要使用Connetion对象来操作事务；而采用Hibernate进行持久化时，需要使用Session对象来操作事务。</p>
<p>Spring提供了如下所示的事务管理器。</p>
<table>
<thead>
<tr>
<th>事务管理器实现类</th>
<th>目标对象</th>
</tr>
</thead>
<tbody>
<tr>
<td>DataSourceTransactionManager</td>
<td>注入DataSource</td>
</tr>
<tr>
<td>HibernateTransactionManager</td>
<td>注入SessionFactory</td>
</tr>
<tr>
<td>JdoTransactionManager</td>
<td>管理JDO事务</td>
</tr>
<tr>
<td>JtaTransactionManager</td>
<td>使用JTA管理事务</td>
</tr>
<tr>
<td>PersistenceBrokerTransactionManager</td>
<td>管理Apache的OJB事务</td>
</tr>
</tbody>
</table>
<p>这些事务的父接口都是PlatformTransactionManager。Spring的事务管理机制是一种典型的策略模式，PlatformTransactionManager代表事务管理接口，该接口定义了三个方法，该接口并不知道底层如何管理事务，但是它的实现类必须提供getTransaction()方法（开启事务）、commit()方法（提交事务）、rollback()方法（回滚事务）的多态实现，这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时，需要底层应用服务器支持，而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异，因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类，如：WebLogicJtaTransactionManager（Oracle的WebLogic服务器提供）、UowJtaTransactionManager（IBM的WebSphere服务器提供）等。</p>
<p>编程式事务管理如下所示。</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
 <beans xmlns="http://www.springframework.org/schema/beans" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

​     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><br><br><br><br>​     &lt;context:component-scan base-package=”com.jackfrued”/&gt;<br><br><br><br>​     <bean id="propertyConfig" ​ class="org.springframework.beans.factory.config.

  PropertyPlaceholderConfigurer"><br><br>​         <property name="location"><br><br>​             <value>jdbc.properties</value><br><br>​         </property><br><br>​     </bean><br><br><br><br>​     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><br><br>​         <property name="driverClassName"><br><br>​             <value>${db.driver}</value><br><br>​         </property><br><br>​         <property name="url"><br><br>​             <value>${db.url}</value><br><br>​         </property><br><br>​         <property name="username"><br><br>​             <value>${db.username}</value><br><br>​         </property><br><br>​         <property name="password"><br><br>​             <value>${db.password}</value><br><br>​         </property><br><br>​     </bean><br><br><br><br>​     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><br><br>​         <property name="dataSource"><br><br>​             <ref bean="dataSource"><br><br>​         </ref></property><br><br>​     </bean><br><br><br><br>​     <!-- JDBC事务管理器 --><br><br>​     <bean id="transactionManager" ​ class="org.springframework.jdbc.datasource.

​       DataSourceTransactionManager" 　scope="singleton"><br><br>​         <property name="dataSource"><br><br>​             <ref bean="dataSource"><br><br>​         </ref></property><br><br>​     </bean><br><br><br><br>​     <!-- 声明事务模板 --><br><br>​     <bean id="transactionTemplate" ​ class="org.springframework.transaction.support.

   TransactionTemplate"><br><br>​         <property name="transactionManager"><br><br>​             <ref bean="transactionManager"><br><br>​         </ref></property><br><br>​     </bean><br><br><br><br></beans>

<p>package com.jackfrued.dao.impl;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.jdbc.core.JdbcTemplate;</p>
<p>import com.jackfrued.dao.EmpDao;</p>
<p>import com.jackfrued.entity.Emp;</p>
<p>@Repository</p>
<p>public class EmpDaoImpl implements EmpDao {</p>
<p>​    @Autowired</p>
<p>​    private JdbcTemplate jdbcTemplate;</p>
<p>​    @Override</p>
<p>​    public boolean save(Emp emp) {</p>
<p>​        String sql = “insert into emp values (?,?,?)”;</p>
<p>​        return jdbcTemplate.update(sql, emp.getId(), emp.getName(), emp.getBirthday()) == 1;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.biz.impl;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.stereotype.Service;</p>
<p>import org.springframework.transaction.TransactionStatus;</p>
<p>import org.springframework.transaction.support.TransactionCallbackWithoutResult;</p>
<p>import org.springframework.transaction.support.TransactionTemplate;</p>
<p>import com.jackfrued.biz.EmpService;</p>
<p>import com.jackfrued.dao.EmpDao;</p>
<p>import com.jackfrued.entity.Emp;</p>
<p>@Service</p>
<p>public class EmpServiceImpl implements EmpService {</p>
<p>​    @Autowired</p>
<p>​    private TransactionTemplate txTemplate;</p>
<p>​    @Autowired</p>
<p>​    private EmpDao empDao;</p>
<p>​    @Override</p>
<p>​    public void addEmp(final Emp emp) {</p>
<p>​        txTemplate.execute(new TransactionCallbackWithoutResult() {</p>
<p>​            @Override</p>
<p>​            protected void doInTransactionWithoutResult(TransactionStatus txStatus) {</p>
<p>​                empDao.save(emp);</p>
<p>​            }</p>
<p>​        });</p>
<p>​    }</p>
<p>}</p>
<p>声明式事务如下图所示，以Spring整合Hibernate 3为例，包括完整的DAO和业务逻辑代码。</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
<beans xmlns="http://www.springframework.org/schema/beans" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="http://www.springframework.org/schema/beans

​           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

​           http://www.springframework.org/schema/context

​           http://www.springframework.org/schema/context/spring-context-3.2.xsd

​           http://www.springframework.org/schema/aop

​           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd

​           http://www.springframework.org/schema/tx

​           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"><br><br><br><br>​    <!-- 配置由Spring IoC容器托管的对象对应的被注解的类所在的包 --><br><br>​    &lt;context:component-scan base-package=”com.jackfrued” /&gt;<br><br><br><br>​    <!-- 配置通过自动生成代理实现AOP功能 --><br><br>​    &lt;aop:aspectj-autoproxy /&gt;<br><br><br><br>​    <!-- 配置数据库连接池 (DBCP) --><br><br>​    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" ​ destroy-method="close"><br><br>​        <!-- 配置驱动程序类 --><br><br>​        <property name="driverClassName" value="com.mysql.jdbc.Driver"><br><br>​        <!-- 配置连接数据库的URL --><br><br>​        <property name="url" value="jdbc:mysql://localhost:3306/myweb"><br><br>​        <!-- 配置访问数据库的用户名 --><br><br>​        <property name="username" value="root"><br><br>​        <!-- 配置访问数据库的口令 --><br><br>​        <property name="password" value="123456"><br><br>​        <!-- 配置最大连接数 --><br><br>​        <property name="maxActive" value="150"><br><br>​        <!-- 配置最小空闲连接数 --><br><br>​        <property name="minIdle" value="5"><br><br>​        <!-- 配置最大空闲连接数 --><br><br>​        <property name="maxIdle" value="20"><br><br>​        <!-- 配置初始连接数 --><br><br>​        <property name="initialSize" value="10"><br><br>​        <!-- 配置连接被泄露时是否生成日志 --><br><br>​        <property name="logAbandoned" value="true"><br><br>​        <!-- 配置是否删除超时连接 --><br><br>​        <property name="removeAbandoned" value="true"><br><br>​        <!-- 配置删除超时连接的超时门限值(以秒为单位) --><br><br>​        <property name="removeAbandonedTimeout" value="120"><br><br>​        <!-- 配置超时等待时间(以毫秒为单位) --><br><br>​        <property name="maxWait" value="5000"><br><br>​        <!-- 配置空闲连接回收器线程运行的时间间隔(以毫秒为单位) --><br><br>​        <property name="timeBetweenEvictionRunsMillis" value="300000"><br><br>​        <!-- 配置连接空闲多长时间后(以毫秒为单位)被断开连接 --><br><br>​        <property name="minEvictableIdleTimeMillis" value="60000"><br><br>​    </property></property></property></property></property></property></property></property></property></property></property></property></property></property></bean><br><br><br><br>​    <!-- 配置Spring提供的支持注解ORM映射的Hibernate会话工厂 --><br><br>​    <bean id="sessionFactory" ​ class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"><br><br>​        <!-- 通过setter注入数据源属性 --><br><br>​        <property name="dataSource" ref="dataSource"><br><br>​        <!-- 配置实体类所在的包 --><br><br>​        <property name="packagesToScan" value="com.jackfrued.entity"><br><br>​        <!-- 配置Hibernate的相关属性 --><br><br>​        <property name="hibernateProperties"><br><br>​            <!-- 在项目调试完成后要删除show_sql和format_sql属性否则对性能有显著影响 --><br><br>​            <value><br><br>​                hibernate.dialect=org.hibernate.dialect.MySQL5Dialect<br><br>​            </value><br><br>​        </property><br><br>​    </property></property></bean><br><br><br><br>​    <!-- 配置Spring提供的Hibernate事务管理器 --><br><br>​    <bean id="transactionManager" ​ class="org.springframework.orm.hibernate3.HibernateTransactionManager"><br><br>​        <!-- 通过setter注入Hibernate会话工厂 --><br><br>​        <property name="sessionFactory" ref="sessionFactory"><br><br>​    </property></bean><br><br><br><br>​    <!-- 配置基于注解配置声明式事务 --><br><br>​    &lt;tx:annotation-driven /&gt;<br><br><br><br></beans>

<p>package com.jackfrued.dao;</p>
<p>import java.io.Serializable;</p>
<p>import java.util.List;</p>
<p>import com.jackfrued.comm.QueryBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>/**</p>
<ul>
<li>数据访问对象接口(以对象为单位封装CRUD操作)</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <e> 实体类型</e></p>
</li>
<li><p>@param <k> 实体标识字段的类型</k></p>
<p>*/</p>
</li>
</ul>
<p>public interface BaseDao &lt;E, K extends Serializable&gt; {</p>
<p>​    /**</p>
<p>​     * 新增</p>
<p>​     * @param entity 业务实体对象</p>
<p>​     * @return 增加成功返回实体对象的标识</p>
<p>​     */</p>
<p>​    public K save(E entity);</p>
<p>​    /**</p>
<p>​     * 删除</p>
<p>​     * @param entity 业务实体对象</p>
<p>​     */</p>
<p>​    public void delete(E entity);</p>
<p>​    /**</p>
<p>​     * 根据ID删除</p>
<p>​     * @param id 业务实体对象的标识</p>
<p>​     * @return 删除成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public boolean deleteById(K id);</p>
<p>​    /**</p>
<p>​     * 修改</p>
<p>​     * @param entity 业务实体对象</p>
<p>​     * @return 修改成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public void update(E entity);</p>
<p>​    /**</p>
<p>​     * 根据ID查找业务实体对象</p>
<p>​     * @param id 业务实体对象的标识</p>
<p>​     * @return 业务实体对象对象或null</p>
<p>​     */</p>
<p>​    public E findById(K id);</p>
<p>​    /**</p>
<p>​     * 根据ID查找业务实体对象</p>
<p>​     * @param id 业务实体对象的标识</p>
<p>​     * @param lazy 是否使用延迟加载</p>
<p>​     * @return 业务实体对象对象</p>
<p>​     */</p>
<p>​    public E findById(K id, boolean lazy);</p>
<p>​    /**</p>
<p>​     * 查找所有业务实体对象</p>
<p>​     * @return 装所有业务实体对象的列表容器</p>
<p>​     */</p>
<p>​    public List<e> findAll();</e></p>
<p>​    /**</p>
<p>​     * 分页查找业务实体对象</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页面大小</p>
<p>​     * @return 查询结果对象</p>
<p>​     */</p>
<p>​    public QueryResult<e> findByPage(int page, int size);</e></p>
<p>​    /**</p>
<p>​     * 分页查找业务实体对象</p>
<p>​     * @param queryBean 查询条件对象</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页面大小</p>
<p>​     * @return 查询结果对象</p>
<p>​     */</p>
<p>​    public QueryResult<e> findByPage(QueryBean queryBean, int page, int size);</e></p>
<p>}</p>
<p>package com.jackfrued.dao;</p>
<p>import java.io.Serializable;</p>
<p>import java.util.List;</p>
<p>import com.jackfrued.comm.QueryBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>/**</p>
<ul>
<li>BaseDao的缺省适配器</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <e> 实体类型</e></p>
</li>
<li><p>@param <k> 实体标识字段的类型</k></p>
<p>*/</p>
</li>
</ul>
<p>public abstract class BaseDaoAdapter&lt;E, K extends Serializable&gt; implements</p>
<p>​        BaseDao&lt;E, K&gt; {</p>
<p>​    @Override</p>
<p>​    public K save(E entity) {</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void delete(E entity) {</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public boolean deleteById(K id) {</p>
<p>​        E entity = findById(id);</p>
<p>​        if(entity != null) {</p>
<p>​            delete(entity);</p>
<p>​            return true;</p>
<p>​        }</p>
<p>​        return false;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void update(E entity) {</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id) {</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id, boolean lazy) {</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public List<e> findAll() {</e></p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(int page, int size) {</e></p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(QueryBean queryBean, int page, int size) {</e></p>
<p>​        return null;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.dao;</p>
<p>import java.io.Serializable;</p>
<p>import java.lang.reflect.ParameterizedType;</p>
<p>import java.util.ArrayList;</p>
<p>import java.util.Collections;</p>
<p>import java.util.List;</p>
<p>import org.hibernate.Query;</p>
<p>import org.hibernate.Session;</p>
<p>import org.hibernate.SessionFactory;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import com.jackfrued.comm.HQLQueryBean;</p>
<p>import com.jackfrued.comm.QueryBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>/**</p>
<ul>
<li>基于Hibernate的BaseDao实现类</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <e> 实体类型</e></p>
</li>
<li><p>@param <k> 主键类型</k></p>
<p>*/</p>
</li>
</ul>
<p>@SuppressWarnings(value = {“unchecked”})</p>
<p>public abstract class BaseDaoHibernateImpl&lt;E, K extends Serializable&gt; extends BaseDaoAdapter&lt;E, K&gt; {</p>
<p>​    @Autowired</p>
<p>​    protected SessionFactory sessionFactory;</p>
<p>​    private Class&lt;?&gt; entityClass;       // 业务实体的类对象</p>
<p>​    private String entityName;          // 业务实体的名字</p>
<p>​    public BaseDaoHibernateImpl() {</p>
<p>​        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();</p>
<p>​        entityClass = (Class&lt;?&gt;) pt.getActualTypeArguments()[0];</p>
<p>​        entityName = entityClass.getSimpleName();</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public K save(E entity) {</p>
<p>​        return (K) sessionFactory.getCurrentSession().save(entity);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void delete(E entity) {</p>
<p>​        sessionFactory.getCurrentSession().delete(entity);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void update(E entity) {</p>
<p>​        sessionFactory.getCurrentSession().update(entity);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id) {</p>
<p>​        return findById(id, false);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id, boolean lazy) {</p>
<p>​        Session session = sessionFactory.getCurrentSession();</p>
<p>​        return (E) (lazy? session.load(entityClass, id) : session.get(entityClass, id));</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public List<e> findAll() {</e></p>
<p>​        return sessionFactory.getCurrentSession().createCriteria(entityClass).list();</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(int page, int size) {</e></p>
<p>​        return new QueryResult<e>(</e></p>
<p>​            findByHQLAndPage(“from “ + entityName , page, size),</p>
<p>​            getCountByHQL(“select count(*) from “ + entityName)</p>
<p>​        );</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(QueryBean queryBean, int page, int size) {</e></p>
<p>​        if(queryBean instanceof HQLQueryBean) {</p>
<p>​            HQLQueryBean hqlQueryBean = (HQLQueryBean) queryBean;</p>
<p>​            return new QueryResult<e>(</e></p>
<p>​                findByHQLAndPage(hqlQueryBean.getQueryString(), page, size, hqlQueryBean.getParameters()),</p>
<p>​                getCountByHQL(hqlQueryBean.getCountString(), hqlQueryBean.getParameters())</p>
<p>​            );</p>
<p>​        }</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和可变参数列表进行查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 可变参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQL(String hql, Object… params) {</e></p>
<p>​        return this.findByHQL(hql, getParamList(params));</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和参数列表进行查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 查询参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQL(String hql, List<object> params) {</object></e></p>
<p>​        List<e> list = createQuery(hql, params).list();</e></p>
<p>​        return list != null &amp;&amp; list.size() &gt; 0 ? list : Collections.EMPTY_LIST;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和参数列表进行分页查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @page 页码</p>
<p>​     * @size 页面大小</p>
<p>​     * @param params 可变参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQLAndPage(String hql, int page, int size, Object… params) {</e></p>
<p>​        return this.findByHQLAndPage(hql, page, size, getParamList(params));</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和参数列表进行分页查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @page 页码</p>
<p>​     * @size 页面大小</p>
<p>​     * @param params 查询参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQLAndPage(String hql, int page, int size, List<object> params) {</object></e></p>
<p>​        List<e> list = createQuery(hql, params)</e></p>
<p>​                .setFirstResult((page - 1) * size)</p>
<p>​                .setMaxResults(size)</p>
<p>​                .list();</p>
<p>​        return list != null &amp;&amp; list.size() &gt; 0 ? list : Collections.EMPTY_LIST;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 查询满足条件的记录数</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 可变参数列表</p>
<p>​     * @return 满足查询条件的总记录数</p>
<p>​     */</p>
<p>​    protected long getCountByHQL(String hql, Object… params) {</p>
<p>​        return this.getCountByHQL(hql, getParamList(params));</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 查询满足条件的记录数</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 参数列表容器</p>
<p>​     * @return 满足查询条件的总记录数</p>
<p>​     */</p>
<p>​    protected long getCountByHQL(String hql, List<object> params) {</object></p>
<p>​        return (Long) createQuery(hql, params).uniqueResult();</p>
<p>​    }</p>
<p>​    // 创建Hibernate查询对象(Query)</p>
<p>​    private Query createQuery(String hql, List<object> params) {</object></p>
<p>​        Query query = sessionFactory.getCurrentSession().createQuery(hql);</p>
<p>​        for(int i = 0; i &lt; params.size(); i++) {</p>
<p>​            query.setParameter(i, params.get(i));</p>
<p>​        }</p>
<p>​        return query;</p>
<p>​    }</p>
<p>​    // 将可变参数列表组装成列表容器</p>
<p>​    private List<object> getParamList(Object… params) {</object></p>
<p>​        List<object> paramList = new ArrayList&lt;&gt;();</object></p>
<p>​        if(params != null) {</p>
<p>​            for(int i = 0; i &lt; params.length; i++) {</p>
<p>​                paramList.add(params[i]);</p>
<p>​            }</p>
<p>​        }</p>
<p>​        return paramList.size() == 0? Collections.EMPTY_LIST : paramList;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>import java.util.List;</p>
<p>/**</p>
<ul>
<li>查询条件的接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface QueryBean {</p>
<p>​    /**</p>
<p>​     * 添加排序字段</p>
<p>​     * @param fieldName 用于排序的字段</p>
<p>​     * @param asc 升序还是降序</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addOrder(String fieldName, boolean asc);</p>
<p>​    /**</p>
<p>​     * 添加排序字段</p>
<p>​     * @param available 是否添加此排序字段</p>
<p>​     * @param fieldName 用于排序的字段</p>
<p>​     * @param asc 升序还是降序</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addOrder(boolean available, String fieldName, boolean asc);</p>
<p>​    /**</p>
<p>​     * 添加查询条件</p>
<p>​     * @param condition 条件</p>
<p>​     * @param params 替换掉条件中参数占位符的参数</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addCondition(String condition, Object… params);</p>
<p>​    /**</p>
<p>​     * 添加查询条件</p>
<p>​     * @param available 是否需要添加此条件</p>
<p>​     * @param condition 条件</p>
<p>​     * @param params 替换掉条件中参数占位符的参数</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addCondition(boolean available, String condition, Object… params);</p>
<p>​    /**</p>
<p>​     * 获得查询语句</p>
<p>​     * @return 查询语句</p>
<p>​     */</p>
<p>​    public String getQueryString();</p>
<p>​    /**</p>
<p>​     * 获取查询记录数的查询语句</p>
<p>​     * @return 查询记录数的查询语句</p>
<p>​     */</p>
<p>​    public String getCountString();</p>
<p>​    /**</p>
<p>​     * 获得查询参数</p>
<p>​     * @return 查询参数的列表容器</p>
<p>​     */</p>
<p>​    public List<object> getParameters();</object></p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>import java.util.List;</p>
<p>/**</p>
<ul>
<li>查询结果</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <t> 泛型参数</t></p>
<p>*/</p>
</li>
</ul>
<p>public class QueryResult<t> {</t></p>
<p>​    private List<t> result;     // 持有查询结果的列表容器</t></p>
<p>​    private long totalRecords;  // 查询到的总记录数</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     */</p>
<p>​    public QueryResult() {</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param result 持有查询结果的列表容器</p>
<p>​     * @param totalRecords 查询到的总记录数</p>
<p>​     */</p>
<p>​    public QueryResult(List<t> result, long totalRecords) {</t></p>
<p>​        this.result = result;</p>
<p>​        this.totalRecords = totalRecords;</p>
<p>​    }</p>
<p>​    public List<t> getResult() {</t></p>
<p>​        return result;</p>
<p>​    }</p>
<p>​    public void setResult(List<t> result) {</t></p>
<p>​        this.result = result;</p>
<p>​    }</p>
<p>​    public long getTotalRecords() {</p>
<p>​        return totalRecords;</p>
<p>​    }</p>
<p>​    public void setTotalRecords(long totalRecords) {</p>
<p>​        this.totalRecords = totalRecords;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.dao;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>/**</p>
<ul>
<li>部门数据访问对象接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface DeptDao extends BaseDao&lt;Dept, Integer&gt; {</p>
<p>​    /**</p>
<p>​     * 分页查询顶级部门</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页码大小</p>
<p>​     * @return 查询结果对象</p>
<p>​     */</p>
<p>​    public QueryResult<dept> findTopDeptByPage(int page, int size);</dept></p>
<p>}</p>
<p>package com.jackfrued.dao.impl;</p>
<p>import java.util.List;</p>
<p>import org.springframework.stereotype.Repository;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>import com.jackfrued.dao.BaseDaoHibernateImpl;</p>
<p>import com.jackfrued.dao.DeptDao;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>@Repository</p>
<p>public class DeptDaoImpl extends BaseDaoHibernateImpl&lt;Dept, Integer&gt; implements DeptDao {</p>
<p>​    private static final String HQL_FIND_TOP_DEPT = “ from Dept as d where d.superiorDept is null “;</p>
<p>​    @Override</p>
<p>​    public QueryResult<dept> findTopDeptByPage(int page, int size) {</dept></p>
<p>​        List<dept> list = findByHQLAndPage(HQL_FIND_TOP_DEPT, page, size);</dept></p>
<p>​        long totalRecords = getCountByHQL(“ select count(*) “ + HQL_FIND_TOP_DEPT);</p>
<p>​        return new QueryResult&lt;&gt;(list, totalRecords);</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>import java.util.List;</p>
<p>/**</p>
<ul>
<li>分页器</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <t> 分页数据对象的类型</t></p>
<p>*/</p>
</li>
</ul>
<p>public class PageBean<t> {</t></p>
<p>​    private static final int DEFAUL_INIT_PAGE = 1;</p>
<p>​    private static final int DEFAULT_PAGE_SIZE = 10;</p>
<p>​    private static final int DEFAULT_PAGE_COUNT = 5;</p>
<p>​    private List<t> data;           // 分页数据</t></p>
<p>​    private PageRange pageRange;    // 页码范围</p>
<p>​    private int totalPage;          // 总页数</p>
<p>​    private int size;               // 页面大小</p>
<p>​    private int currentPage;        // 当前页码</p>
<p>​    private int pageCount;          // 页码数量</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     * @param size 页码大小</p>
<p>​     * @param pageCount 页码数量</p>
<p>​     */</p>
<p>​    public PageBean(int currentPage, int size, int pageCount) {</p>
<p>​        this.currentPage = currentPage &gt; 0 ? currentPage : 1;</p>
<p>​        this.size = size &gt; 0 ? size : DEFAULT_PAGE_SIZE;</p>
<p>​        this.pageCount = pageCount &gt; 0 ? size : DEFAULT_PAGE_COUNT;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     * @param size 页码大小</p>
<p>​     */</p>
<p>​    public PageBean(int currentPage, int size) {</p>
<p>​        this(currentPage, size, DEFAULT_PAGE_COUNT);</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     */</p>
<p>​    public PageBean(int currentPage) {</p>
<p>​        this(currentPage, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_COUNT);</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     */</p>
<p>​    public PageBean() {</p>
<p>​        this(DEFAUL_INIT_PAGE, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_COUNT);</p>
<p>​    }</p>
<p>​    public List<t> getData() {</t></p>
<p>​        return data;</p>
<p>​    }</p>
<p>​    public int getStartPage() {</p>
<p>​        return pageRange != null ? pageRange.getStartPage() : 1;</p>
<p>​    }</p>
<p>​    public int getEndPage() {</p>
<p>​        return pageRange != null ? pageRange.getEndPage() : 1;</p>
<p>​    }</p>
<p>​    public long getTotalPage() {</p>
<p>​        return totalPage;</p>
<p>​    }</p>
<p>​    public int getSize() {</p>
<p>​        return size;</p>
<p>​    }</p>
<p>​    public int getCurrentPage() {</p>
<p>​        return currentPage;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 将查询结果转换为分页数据</p>
<p>​     * @param queryResult 查询结果对象</p>
<p>​     */</p>
<p>​    public void transferQueryResult(QueryResult<t> queryResult) {</t></p>
<p>​        long totalRecords = queryResult.getTotalRecords();</p>
<p>​        data = queryResult.getResult();</p>
<p>​        totalPage = (int) ((totalRecords + size - 1) / size); </p>
<p>​        totalPage = totalPage &gt;= 0 ? totalPage : Integer.MAX_VALUE;</p>
<p>​        this.pageRange = new PageRange(pageCount, currentPage, totalPage);</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>/**</p>
<ul>
<li>页码范围</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public class PageRange {</p>
<p>​    private int startPage;  // 起始页码</p>
<p>​    private int endPage;    // 终止页码</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param pageCount 总共显示几个页码</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     * @param totalPage 总页数</p>
<p>​     */</p>
<p>​    public PageRange(int pageCount, int currentPage, int totalPage) {</p>
<p>​        startPage = currentPage - (pageCount - 1) / 2;</p>
<p>​        endPage = currentPage + pageCount / 2;</p>
<p>​        if(startPage &lt; 1) {</p>
<p>​            startPage = 1;</p>
<p>​            endPage = totalPage &gt; pageCount ? pageCount : totalPage;</p>
<p>​        }</p>
<p>​        if (endPage &gt; totalPage) {</p>
<p>​            endPage = totalPage;</p>
<p>​            startPage = (endPage - pageCount &gt; 0) ? endPage - pageCount + 1 : 1;</p>
<p>​        }</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 获得起始页页码</p>
<p>​     * @return 起始页页码</p>
<p>​     */</p>
<p>​    public int getStartPage() {</p>
<p>​        return startPage;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 获得终止页页码</p>
<p>​     * @return 终止页页码</p>
<p>​     */</p>
<p>​    public int getEndPage() {</p>
<p>​        return endPage;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.biz;</p>
<p>import com.jackfrued.comm.PageBean;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>/**</p>
<ul>
<li>部门业务逻辑接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface DeptService {</p>
<p>​    /**</p>
<p>​     * 创建新的部门</p>
<p>​     * @param department 部门对象</p>
<p>​     * @return 创建成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public boolean createNewDepartment(Dept department);</p>
<p>​    /**</p>
<p>​     * 删除指定部门</p>
<p>​     * @param id 要删除的部门的编号</p>
<p>​     * @return 删除成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public boolean deleteDepartment(Integer id);</p>
<p>​    /**</p>
<p>​     * 分页获取顶级部门</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页码大小</p>
<p>​     * @return 部门对象的分页器对象</p>
<p>​     */</p>
<p>​    public PageBean<dept> getTopDeptByPage(int page, int size);</dept></p>
<p>}</p>
<p>package com.jackfrued.biz.impl;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.stereotype.Service;</p>
<p>import org.springframework.transaction.annotation.Transactional;</p>
<p>import com.jackfrued.biz.DeptService;</p>
<p>import com.jackfrued.comm.PageBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>import com.jackfrued.dao.DeptDao;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>@Service</p>
<p>@Transactional  // 声明式事务的注解</p>
<p>public class DeptServiceImpl implements DeptService {</p>
<p>​    @Autowired</p>
<p>​    private DeptDao deptDao;</p>
<p>​    @Override</p>
<p>​    public boolean createNewDepartment(Dept department) {</p>
<p>​        return deptDao.save(department) != null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public boolean deleteDepartment(Integer id) {</p>
<p>​        return deptDao.deleteById(id);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public PageBean<dept> getTopDeptByPage(int page, int size) {</dept></p>
<p>​        QueryResult<dept> queryResult = deptDao.findTopDeptByPage(page, size);</dept></p>
<p>​        PageBean<dept> pageBean = new PageBean&lt;&gt;(page, size);</dept></p>
<p>​        pageBean.transferQueryResult(queryResult);</p>
<p>​        return pageBean;</p>
<p>​    }</p>
<p>}</p>
<h3 id="如何在Web项目中配置Spring的IoC容器？"><a href="#如何在Web项目中配置Spring的IoC容器？" class="headerlink" title="如何在Web项目中配置Spring的IoC容器？"></a>如何在Web项目中配置Spring的IoC容器？</h3><p> 答：如果需要在Web项目中使用Spring的IoC容器，可以在Web项目配置文件web.xml中做出如下配置：</p>
<p><context-param></context-param></p>
<p>​    <param-name>contextConfigLocation</param-name></p>
<p>​    <param-value>classpath:applicationContext.xml</param-value></p>
<p></p>
<listener><br><br>​    <listener-class><br><br>​        org.springframework.web.context.ContextLoaderListener<br><br>​    </listener-class><br><br></listener>



<h3 id="如何在Spring-IoC容器中配置数据源？"><a href="#如何在Spring-IoC容器中配置数据源？" class="headerlink" title="如何在Spring IoC容器中配置数据源？"></a>如何在Spring IoC容器中配置数据源？</h3><p>答：<br>DBCP配置：</p>
<bean id="dataSource" ​ class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><br><br>​    <property name="driverClassName" value="${jdbc.driverClassName}"><br><br>​    <property name="url" value="${jdbc.url}"><br><br>​    <property name="username" value="${jdbc.username}"><br><br>​    <property name="password" value="${jdbc.password}"><br><br></property></property></property></property></bean>



<p>&lt;context:property-placeholder location=”jdbc.properties”/&gt;</p>
<p>C3P0配置：</p>
<bean id="dataSource" ​ class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><br><br>​    <property name="driverClass" value="${jdbc.driverClassName}"><br><br>​    <property name="jdbcUrl" value="${jdbc.url}"><br><br>​    <property name="user" value="${jdbc.username}"><br><br>​    <property name="password" value="${jdbc.password}"><br><br></property></property></property></property></bean>



<p>&lt;context:property-placeholder location=”jdbc.properties”/&gt;</p>
<p>提示： DBCP的详细配置在第153题中已经完整的展示过了。</p>
<h3 id="如何配置配置事务增强？"><a href="#如何配置配置事务增强？" class="headerlink" title="如何配置配置事务增强？"></a>如何配置配置事务增强？</h3><p>答：</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
<beans xmlns="http://www.springframework.org/schema/beans" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="

​     http://www.springframework.org/schema/beans

​     http://www.springframework.org/schema/beans/spring-beans.xsd

​     http://www.springframework.org/schema/tx

​     http://www.springframework.org/schema/tx/spring-tx.xsd

​     http://www.springframework.org/schema/aop

​     http://www.springframework.org/schema/aop/spring-aop.xsd"><br><br><br><br>  <!-- this is the service object that we want to make transactional --><br><br>  <bean id="fooService" class="x.y.service.DefaultFooService"><br><br><br><br>  <!-- the transactional advice --><br><br>  &lt;tx:advice id=”txAdvice” transaction-manager=”txManager”&gt;<br><br>  <!-- the transactional semantics... --><br><br>  tx:attributes<br><br>​    <!-- all methods starting with 'get' are read-only --><br><br>​    &lt;tx:method name=”get<em>“ read-only=”true”/&gt;<br><br>​    <!-- other methods use the default transaction settings (see below) --><br><br>​    &lt;tx:method name=”</em>“/&gt;<br><br>  /tx:attributes<br><br>  /tx:advice<br><br><br><br>  <!-- ensure that the above transactional advice runs for any execution

​    of an operation defined by the FooService interface --><br><br>  aop:config<br><br>  &lt;aop:pointcut id=”fooServiceOperation”<br><br>​    expression=”execution(<em> x.y.service.FooService.</em>(..))”/&gt;<br><br>  &lt;aop:advisor advice-ref=”txAdvice” pointcut-ref=”fooServiceOperation”/&gt;<br><br>  /aop:config<br><br><br><br>  <!-- don't forget the DataSource --><br><br>  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" ​ destroy-method="close"><br><br>  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"><br><br>  <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"><br><br>  <property name="username" value="scott"><br><br>  <property name="password" value="tiger"><br><br>  </property></property></property></property></bean><br><br><br><br>  <!-- similarly, don't forget the PlatformTransactionManager --><br><br>  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><br><br>  <property name="dataSource" ref="dataSource"><br><br>  </property></bean><br><br><br><br>  <!-- other <bean/> definitions here --><br><br><br><br></bean></beans>

<h3 id="选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？"><a href="#选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？" class="headerlink" title="选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？"></a>选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？</h3><p>答：可以从以下几个方面作答： </p>
<ul>
<li>非侵入式：支持基于POJO的编程模式，不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。 </li>
<li>IoC容器：IoC容器帮助应用程序管理对象以及对象之间的依赖关系，对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码，因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了IoC容器，程序员再也不需要自己编写工厂、单例，这一点特别符合Spring的精神”不要重复的发明轮子”。 </li>
<li>AOP（面向切面编程）：将所有的横切关注功能封装到切面（aspect）中，通过配置的方式将横切关注功能动态添加到目标代码上，进一步实现了业务逻辑和系统服务之间的分离。另一方面，有了AOP程序员可以省去很多自己写代理类的工作。 </li>
<li>MVC：Spring的MVC框架是非常优秀的，从各个方面都可以甩Struts 2几条街，为Web表示层提供了更好的解决方案。 </li>
<li>事务管理：Spring以宽广的胸怀接纳多种持久层技术，并且为其提供了声明式的事务管理，在不需要任何一行代码的情况下就能够完成事务管理。 </li>
<li>其他：选择Spring框架的原因还远不止于此，Spring为Java企业级开发提供了一站式选择，你可以在需要的时候使用它的部分和全部，更重要的是，你甚至可以在感觉不到Spring存在的情况下，在你的项目中使用Spring提供的各种优秀的功能。</li>
</ul>
<h3 id="Spring-IoC容器配置Bean的方式？"><a href="#Spring-IoC容器配置Bean的方式？" class="headerlink" title="Spring IoC容器配置Bean的方式？"></a>Spring IoC容器配置Bean的方式？</h3><p>答： </p>
<ul>
<li>基于XML文件进行配置。 </li>
<li>基于注解进行配置。 </li>
<li>基于Java程序进行配置（Spring 3+）</li>
</ul>
<p>package com.jackfrued.bean;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.stereotype.Component;</p>
<p>@Component</p>
<p>public class Person {</p>
<p>​    private String name;</p>
<p>​    private int age;</p>
<p>​    @Autowired</p>
<p>​    private Car car;</p>
<p>​    public Person(String name, int age) {</p>
<p>​        this.name = name;</p>
<p>​        this.age = age;</p>
<p>​    }</p>
<p>​    public void setCar(Car car) {</p>
<p>​        this.car = car;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public String toString() {</p>
<p>​        return “Person [name=” + name + “, age=” + age + “, car=” + car + “]”;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.bean;</p>
<p>import org.springframework.stereotype.Component;</p>
<p>@Component</p>
<p>public class Car {</p>
<p>​    private String brand;</p>
<p>​    private int maxSpeed;</p>
<p>​    public Car(String brand, int maxSpeed) {</p>
<p>​        this.brand = brand;</p>
<p>​        this.maxSpeed = maxSpeed;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public String toString() {</p>
<p>​        return “Car [brand=” + brand + “, maxSpeed=” + maxSpeed + “]”;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.config;</p>
<p>import org.springframework.context.annotation.Bean;</p>
<p>import org.springframework.context.annotation.Configuration;</p>
<p>import com.jackfrued.bean.Car;</p>
<p>import com.jackfrued.bean.Person;</p>
<p>@Configuration</p>
<p>public class AppConfig {</p>
<p>​    @Bean</p>
<p>​    public Car car() {</p>
<p>​        return new Car(“Benz”, 320);</p>
<p>​    }</p>
<p>​    @Bean</p>
<p>​    public Person person() {</p>
<p>​        return new Person(“骆昊”, 34);</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.test;</p>
<p>import org.springframework.context.ConfigurableApplicationContext;</p>
<p>import org.springframework.context.annotation.AnnotationConfigApplicationContext;</p>
<p>import com.jackfrued.bean.Person;</p>
<p>import com.jackfrued.config.AppConfig;</p>
<p>class Test {</p>
<p>​    public static void main(String[] args) {</p>
<p>​        // TWR (Java 7+)</p>
<p>​        try(ConfigurableApplicationContext factory = new AnnotationConfigApplicationContext(AppConfig.class)) {</p>
<p>​            Person person = factory.getBean(Person.class);</p>
<p>​            System.out.println(person);</p>
<p>​        }</p>
<p>​    }</p>
<p>}</p>
<h3 id="阐述Spring框架中Bean的生命周期？"><a href="#阐述Spring框架中Bean的生命周期？" class="headerlink" title="阐述Spring框架中Bean的生命周期？"></a>阐述Spring框架中Bean的生命周期？</h3><p>答：<br>① Spring IoC容器找到关于Bean的定义并实例化该Bean。<br>② Spring IoC容器对Bean进行依赖注入。<br>③ 如果Bean实现了BeanNameAware接口，则将该Bean的id传给setBeanName方法。<br>④ 如果Bean实现了BeanFactoryAware接口，则将BeanFactory对象传给setBeanFactory方法。<br>⑤ 如果Bean实现了BeanPostProcessor接口，则调用其postProcessBeforeInitialization方法。<br>⑥ 如果Bean实现了InitializingBean接口，则调用其afterPropertySet方法。<br>⑦ 如果有和Bean关联的BeanPostProcessors对象，则这些对象的postProcessAfterInitialization方法被调用。<br>⑧ 当销毁Bean实例时，如果Bean实现了DisposableBean接口，则调用其destroy方法。</p>
<h3 id="依赖注入时如何注入集合属性？"><a href="#依赖注入时如何注入集合属性？" class="headerlink" title="依赖注入时如何注入集合属性？"></a>依赖注入时如何注入集合属性？</h3><p>答：可以在定义Bean属性时，通过<list> / <set> / <map> / <props>分别为其注入列表、集合、映射和键值都是字符串的映射属性。</props></map></set></list></p>
<h3 id="Spring中的自动装配有哪些限制？"><a href="#Spring中的自动装配有哪些限制？" class="headerlink" title="Spring中的自动装配有哪些限制？"></a>Spring中的自动装配有哪些限制？</h3><p> 答： </p>
<ul>
<li>如果使用了构造器注入或者setter注入，那么将覆盖自动装配的依赖关系。 </li>
<li>基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。 </li>
<li>优先考虑使用显式的装配来进行更精确的依赖注入而不是使用自动装配。</li>
</ul>
<h3 id="在Web项目中如何获得Spring的IoC容器？"><a href="#在Web项目中如何获得Spring的IoC容器？" class="headerlink" title="在Web项目中如何获得Spring的IoC容器？"></a>在Web项目中如何获得Spring的IoC容器？</h3><p>答：</p>
<p>WebApplicationContext ctx = </p>
<p>WebApplicationContextUtils.getWebApplicationContext(servletContext);</p>
<h3 id="Spring由哪些模块组成？"><a href="#Spring由哪些模块组成？" class="headerlink" title="Spring由哪些模块组成？"></a>Spring由哪些模块组成？</h3><p>以下是Spring 框架的基本模块：</p>
<p>Core module</p>
<p>Bean module</p>
<p>Context module</p>
<p>Expression Language module</p>
<p>JDBC module</p>
<p>ORM module</p>
<p>OXM module</p>
<p>Java Messaging Service(JMS) module</p>
<p>Transaction module</p>
<p>Web module</p>
<p>Web-Servlet module</p>
<p>Web-Struts module</p>
<p>Web-Portlet module</p>
<h3 id="【Spring】什么是Spring-IOC-容器？"><a href="#【Spring】什么是Spring-IOC-容器？" class="headerlink" title="【Spring】什么是Spring IOC 容器？"></a>【Spring】<strong>什么是Spring IOC 容器？</strong></h3><p>Spring IOC 负责创建对象，管理对象（通过依赖注入（DI），装配对象，配置对象，并且管理这些对象的整个生命周期。</p>
<h3 id="【Spring】IOC的优点是什么？"><a href="#【Spring】IOC的优点是什么？" class="headerlink" title="【Spring】IOC的优点是什么？"></a>【Spring】<strong>IOC的优点是什么？</strong></h3><p>IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试，单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。</p>
<h3 id="【Spring】ApplicationContext通常的实现是什么？"><a href="#【Spring】ApplicationContext通常的实现是什么？" class="headerlink" title="【Spring】ApplicationContext通常的实现是什么？"></a>【Spring】<strong>ApplicationContext通常的实现是什么？</strong></h3><p>FileSystemXmlApplicationContext ：此容器从一个XML文件中加载beans的定义，XML Bean 配置文件的全路径名必须提供给它的构造函数。</p>
<p>ClassPathXmlApplicationContext：此容器也从一个XML文件中加载beans的定义，这里，你需要正确设置classpath因为这个容器将在classpath里找bean配置。</p>
<p>WebXmlApplicationContext：此容器加载一个XML文件，此文件定义了一个WEB应用的所有bean。</p>
<h3 id="【Spring】Bean-工厂和-Application-contexts-有什么区别？"><a href="#【Spring】Bean-工厂和-Application-contexts-有什么区别？" class="headerlink" title="【Spring】Bean 工厂和 Application contexts  有什么区别？"></a>【Spring】<strong>Bean 工厂和 Application contexts  有什么区别？</strong></h3><p>Application contexts提供一种方法处理文本消息，一个通常的做法是加载文件资源（比如镜像），它们可以向注册为监听器的bean发布事件。另外，在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作，可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口，该接口的实现以可插拔的方式提供获取本地化消息的方法。</p>
<h3 id="【Spring】什么是Spring的依赖注入？"><a href="#【Spring】什么是Spring的依赖注入？" class="headerlink" title="【Spring】什么是Spring的依赖注入？"></a>【Spring】<strong>什么是Spring的依赖注入？</strong></h3><p>依赖注入，是IOC的一个方面，是个通常的概念，它有多种解释。这概念是说你不用创建对象，而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务，但是要在配置文件里描述哪些组件需要哪些服务，之后一个容器（IOC容器）负责把他们组装起来。</p>
<h3 id="【Spring】有哪些不同类型的IOC（依赖注入）方式？"><a href="#【Spring】有哪些不同类型的IOC（依赖注入）方式？" class="headerlink" title="【Spring】有哪些不同类型的IOC（依赖注入）方式？"></a>【Spring】<strong>有哪些不同类型的IOC（依赖注入）方式？</strong></h3><p>构造器依赖注入：构造器依赖注入通过容器触发一个类的构造器来实现的，该类有一系列参数，每个参数代表一个对其他类的依赖。</p>
<p>Setter方法注入：Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后，调用该bean的setter方法，即实现了基于setter的依赖注入。</p>
<h3 id="【Spring】哪种依赖注入方式你建议使用，构造器注入，还是-Setter方法注入？"><a href="#【Spring】哪种依赖注入方式你建议使用，构造器注入，还是-Setter方法注入？" class="headerlink" title="【Spring】哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入？"></a>【Spring】<strong>哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入？</strong></h3><p>你两种依赖方式都可以使用，构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖，setter方法实现可选依赖。</p>
<h3 id="【Spring】什么是Spring-beans？"><a href="#【Spring】什么是Spring-beans？" class="headerlink" title="【Spring】什么是Spring beans？"></a>【Spring】<strong>什么是Spring beans？</strong></h3><p>Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化，装配，和管理。这些beans通过容器中配置的元数据创建。比如，以XML文件中<bean> 的形式定义。</bean></p>
<p>Spring 框架定义的beans都是单件beans。在bean tag中有个属性”singleton”，如果它被赋为TRUE，bean 就是单件，否则就是一个 prototype bean。默认是TRUE，所以所有在Spring框架中的beans 缺省都是单件。</p>
<h3 id="【Spring】一个-Spring-Bean-定义-包含什么？"><a href="#【Spring】一个-Spring-Bean-定义-包含什么？" class="headerlink" title="【Spring】一个 Spring Bean 定义 包含什么？"></a>【Spring】<strong>一个 Spring Bean 定义 包含什么？</strong></h3><p>一个Spring Bean 的定义包含容器必知的所有配置元数据，包括如何创建一个bean，它的生命周期详情及它的依赖。</p>
<h3 id="【Spring】如何给Spring-容器提供配置元数据？"><a href="#【Spring】如何给Spring-容器提供配置元数据？" class="headerlink" title="【Spring】如何给Spring 容器提供配置元数据？"></a>【Spring】<strong>如何给Spring 容器提供配置元数据？</strong></h3><p>这里有三种重要的方法给Spring 容器提供配置元数据。</p>
<p>XML配置文件。</p>
<p>基于注解的配置。</p>
<p>基于java的配置。</p>
<h3 id="【Spring】解释Spring支持的几种bean的作用域"><a href="#【Spring】解释Spring支持的几种bean的作用域" class="headerlink" title="【Spring】解释Spring支持的几种bean的作用域"></a>【Spring】<strong>解释Spring支持的几种bean的作用域</strong></h3><p>Spring框架支持以下五种bean的作用域：</p>
<p>singleton : bean在每个Spring ioc 容器中只有一个实例。</p>
<p>prototype：一个bean的定义可以有多个实例。</p>
<p>request：每次http请求都会创建一个bean，该作用域仅在基于web的Spring ApplicationContext情形下有效。</p>
<p>session：在一个HTTP Session中，一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。</p>
<p>global-session：在一个全局的HTTP Session中，一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。</p>
<p>缺省的Spring bean 的作用域是Singleton。</p>
<h3 id="【Spring】Spring框架中的单例bean是线程安全的吗？"><a href="#【Spring】Spring框架中的单例bean是线程安全的吗？" class="headerlink" title="【Spring】Spring框架中的单例bean是线程安全的吗？"></a>【Spring】<strong>Spring框架中的单例bean是线程安全的吗？</strong></h3><p>不，Spring框架中的单例bean不是线程安全的。</p>
<h3 id="【Spring】解释Spring框架中bean的生命周期"><a href="#【Spring】解释Spring框架中bean的生命周期" class="headerlink" title="【Spring】解释Spring框架中bean的生命周期"></a>【Spring】<strong>解释Spring框架中bean的生命周期</strong></h3><p>Spring容器 从XML 文件中读取bean的定义，并实例化bean。</p>
<p>Spring根据bean的定义填充所有的属性。</p>
<p>如果bean实现了BeanNameAware 接口，Spring 传递bean 的ID 到 setBeanName方法。</p>
<p>如果Bean 实现了 BeanFactoryAware 接口， Spring传递beanfactory 给setBeanFactory 方法。</p>
<p>如果有任何与bean相关联的BeanPostProcessors，Spring会在postProcesserBeforeInitialization()方法内调用它们。</p>
<p>如果bean实现IntializingBean了，调用它的afterPropertySet方法，如果bean声明了初始化方法，调用此初始化方法。</p>
<p>如果有BeanPostProcessors 和bean 关联，这些bean的postProcessAfterInitialization() 方法将被调用。</p>
<p>如果bean实现了 DisposableBean，它将调用destroy()方法。</p>
<h3 id="【Spring】哪些是重要的bean生命周期方法？-你能重载它们吗？"><a href="#【Spring】哪些是重要的bean生命周期方法？-你能重载它们吗？" class="headerlink" title="【Spring】哪些是重要的bean生命周期方法？ 你能重载它们吗？"></a>【Spring】<strong>哪些是重要的bean生命周期方法？ 你能重载它们吗？</strong></h3><p>有两个重要的bean 生命周期方法，第一个是setup ， 它是在容器加载bean的时候被调用。第二个方法是 teardown  它是在容器卸载类的时候被调用。</p>
<p>The bean 标签有两个重要的属性（init-method和destroy-method）。用它们你可以自己定制初始化和注销方法。它们也有相应的注解（@PostConstruct和@PreDestroy）。</p>
<h3 id="【Spring】在-Spring中如何注入一个java集合？"><a href="#【Spring】在-Spring中如何注入一个java集合？" class="headerlink" title="【Spring】在 Spring中如何注入一个java集合？"></a>【Spring】<strong>在 Spring中如何注入一个java集合？</strong></h3><p>Spring提供以下几种集合的配置元素：</p>
<p><list>类型用于注入一列值，允许有相同的值。</list></p>
<p><set> 类型用于注入一组值，不允许有相同的值。</set></p>
<p><map> 类型用于注入一组键值对，键和值都可以为任意类型。</map></p>
<p><props>类型用于注入一组键值对，键和值都只能为String类型。</props></p>
<h3 id="【Spring】什么是bean装配？"><a href="#【Spring】什么是bean装配？" class="headerlink" title="【Spring】什么是bean装配？"></a>【Spring】<strong>什么是bean装配？</strong></h3><p>装配，或bean 装配是指在Spring 容器中把bean组装到一起，前提是容器需要知道bean的依赖关系，如何通过依赖注入来把它们装配到一起。</p>
<h3 id="【Spring】什么是bean的自动装配？"><a href="#【Spring】什么是bean的自动装配？" class="headerlink" title="【Spring】什么是bean的自动装配？"></a>【Spring】<strong>什么是bean的自动装配？</strong></h3><p>Spring 容器能够自动装配相互合作的bean，这意味着容器不需要<constructor-arg>和<property>配置，能通过Bean工厂自动处理bean之间的协作。</property></constructor-arg></p>
<h3 id="【Spring】解释不同方式的自动装配"><a href="#【Spring】解释不同方式的自动装配" class="headerlink" title="【Spring】解释不同方式的自动装配"></a>【Spring】<strong>解释不同方式的自动装配</strong></h3><p>有五种自动装配的方式，可以用来指导Spring容器用自动装配方式来进行依赖注入</p>
<p>no：默认的方式是不进行自动装配，通过显式设置ref 属性来进行装配。</p>
<p>byName：通过参数名 自动装配，Spring容器在配置文件中发现bean的autowire属性被设置成byname，之后容器试图匹配、装配和该bean的属性具有相同名字的bean。</p>
<p>byType：通过参数类型自动装配，Spring容器在配置文件中发现bean的autowire属性被设置成byType，之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件，则抛出错误。</p>
<p>constructor：这个方式类似于byType， 但是要提供给构造器参数，如果没有确定的带参数的构造器参数类型，将会抛出异常。</p>
<p>autodetect：首先尝试使用constructor来自动装配，如果无法工作，则使用byType方式。</p>
<h3 id="【Spring】自动装配有哪些局限性？"><a href="#【Spring】自动装配有哪些局限性？" class="headerlink" title="【Spring】自动装配有哪些局限性？"></a>【Spring】<strong>自动装配有哪些局限性？</strong></h3><p>自动装配的局限性是：</p>
<p>重写：你仍需用 <constructor-arg>和 <property> 配置来定义依赖，意味着总要重写自动装配。</property></constructor-arg></p>
<p>基本数据类型：你不能自动装配简单的属性，如基本数据类型，String字符串，和类。</p>
<p>模糊特性：自动装配不如显式装配精确，如果有可能，建议使用显式装配。</p>
<h3 id="【Spring】你可以在Spring中注入一个null-和一个空字符串吗？"><a href="#【Spring】你可以在Spring中注入一个null-和一个空字符串吗？" class="headerlink" title="【Spring】你可以在Spring中注入一个null 和一个空字符串吗？"></a>【Spring】<strong>你可以在Spring中注入一个null 和一个空字符串吗？</strong></h3><p>可以</p>
<h3 id="【Spring】什么是基于Java的Spring注解配置-给一些注解的例子"><a href="#【Spring】什么是基于Java的Spring注解配置-给一些注解的例子" class="headerlink" title="【Spring】什么是基于Java的Spring注解配置? 给一些注解的例子"></a>【Spring】<strong>什么是基于Java的Spring注解配置? 给一些注解的例子</strong></h3><p>基于Java的配置，允许你在少量的Java注解的帮助下，进行你的大部分Spring配置而非通过XML文件。</p>
<p>以@Configuration 注解为例，它用来标记类可以当做一个bean的定义，被Spring IOC容器使用。另一个例子是@Bean注解，它表示此方法将要返回一个对象，作为一个bean注册进Spring应用上下文。点击这里学习JAVA几大元注解。</p>
<h3 id="【Spring】什么是基于注解的容器配置？"><a href="#【Spring】什么是基于注解的容器配置？" class="headerlink" title="【Spring】什么是基于注解的容器配置？"></a>【Spring】<strong>什么是基于注解的容器配置？</strong></h3><p>相对于XML文件，注解型的配置依赖于通过字节码元数据装配组件，而非尖括号的声明。</p>
<p>开发者通过在相应的类，方法或属性上使用注解的方式，直接组件类中进行配置，而不是使用xml表述bean的装配关系。</p>
<h3 id="【Spring】怎样开启注解装配？"><a href="#【Spring】怎样开启注解装配？" class="headerlink" title="【Spring】怎样开启注解装配？"></a>【Spring】<strong>怎样开启注解装配？</strong></h3><p>注解装配在默认情况下是不开启的，为了使用注解装配，我们必须在Spring配置文件中配置 context:annotation-config/元素。</p>
<h3 id="【Spring】-Required-注解"><a href="#【Spring】-Required-注解" class="headerlink" title="【Spring】@Required  注解"></a>【Spring】<strong>@Required  注解</strong></h3><p>这个注解表明bean的属性必须在配置的时候设置，通过一个bean定义的显式的属性值或通过自动装配，若@Required注解的bean属性未被设置，容器将抛出BeanInitializationException。</p>
<h3 id="【Spring】-Autowired-注解"><a href="#【Spring】-Autowired-注解" class="headerlink" title="【Spring】@Autowired 注解"></a>【Spring】<strong>@Autowired 注解</strong></h3><p>@Autowired 注解提供了更细粒度的控制，包括在何处以及如何完成自动装配。它的用法和@Required一样，修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。</p>
<h3 id="【Spring】-Qualifier-注解"><a href="#【Spring】-Qualifier-注解" class="headerlink" title="【Spring】@Qualifier 注解"></a>【Spring】<strong>@Qualifier 注解</strong></h3><p>当有多个相同类型的bean却只有一个需要自动装配时，将@Qualifier 注解和@Autowire 注解结合使用以消除这种混淆，指定需要装配的确切的bean。</p>
<h3 id="【Spring】在Spring框架中如何更有效地使用JDBC？"><a href="#【Spring】在Spring框架中如何更有效地使用JDBC？" class="headerlink" title="【Spring】在Spring框架中如何更有效地使用JDBC？"></a>【Spring】<strong>在Spring框架中如何更有效地使用JDBC？</strong></h3><p>使用SpringJDBC 框架，资源管理和错误处理的代价都会被减轻。所以开发者只需写statements 和 queries从数据存取数据，JDBC也可以在Spring框架提供的模板类的帮助下更有效地被使用，这个模板叫JdbcTemplate （例子见这里here）</p>
<h3 id="【Spring】-JdbcTemplate"><a href="#【Spring】-JdbcTemplate" class="headerlink" title="【Spring】 JdbcTemplate"></a>【Spring】 JdbcTemplate</h3><p>JdbcTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象，执行写好的或可调用的数据库操作语句，提供自定义的数据错误处理。</p>
<h3 id="【Spring】Spring对DAO的支持"><a href="#【Spring】Spring对DAO的支持" class="headerlink" title="【Spring】Spring对DAO的支持"></a>【Spring】<strong>Spring对DAO的支持</strong></h3><p>Spring对数据访问对象（DAO）的支持旨在简化它和数据访问技术如JDBC，Hibernate or JDO 结合使用。这使我们可以方便切换持久层。编码时也不用担心会捕获每种技术特有的异常。</p>
<h3 id="【Spring】使用Spring通过什么方式访问Hibernate？"><a href="#【Spring】使用Spring通过什么方式访问Hibernate？" class="headerlink" title="【Spring】使用Spring通过什么方式访问Hibernate？"></a>【Spring】<strong>使用Spring通过什么方式访问Hibernate？</strong></h3><p>在Spring中有两种方式访问Hibernate：</p>
<p>控制反转  Hibernate Template和 Callback</p>
<p>继承 HibernateDAOSupport提供一个AOP 拦截器</p>
<h3 id="【Spring】Spring支持的ORM"><a href="#【Spring】Spring支持的ORM" class="headerlink" title="【Spring】Spring支持的ORM"></a>【Spring】<strong>Spring支持的ORM</strong></h3><p>Spring支持以下ORM：</p>
<p>Hibernate</p>
<p>iBatis</p>
<p>JPA (Java Persistence API)</p>
<p>TopLink</p>
<p>JDO (Java Data Objects)</p>
<p>OJB</p>
<h3 id="【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？"><a href="#【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？" class="headerlink" title="【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？"></a>【Spring】<strong>如何通过HibernateDaoSupport将Spring和Hibernate结合起来？</strong></h3><p>用Spring的 SessionFactory 调用 LocalSessionFactory。集成过程分三步：</p>
<p>配置the Hibernate SessionFactory</p>
<p>继承HibernateDaoSupport实现一个DAO</p>
<p>在AOP支持的事务中装配</p>
<h3 id="【Spring】Spring支持的事务管理类型"><a href="#【Spring】Spring支持的事务管理类型" class="headerlink" title="【Spring】Spring支持的事务管理类型"></a>【Spring】<strong>Spring支持的事务管理类型</strong></h3><p>Spring支持两种类型的事务管理：</p>
<p>编程式事务管理：这意味你通过编程的方式管理事务，给你带来极大的灵活性，但是难维护。</p>
<p>声明式事务管理：这意味着你可以将业务代码和事务管理分离，你只需用注解和XML配置来管理事务。</p>
<h3 id="【Spring】Spring框架的事务管理有哪些优点？"><a href="#【Spring】Spring框架的事务管理有哪些优点？" class="headerlink" title="【Spring】Spring框架的事务管理有哪些优点？"></a>【Spring】<strong>Spring框架的事务管理有哪些优点？</strong></h3><p>它为不同的事务API  如 JTA，JDBC，Hibernate，JPA 和JDO，提供一个不变的编程模式。</p>
<p>它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如</p>
<p>它支持声明式事务管理。</p>
<p>它和Spring各种数据访问抽象层很好得集成。</p>
<h3 id="【Spring】你更倾向用那种事务管理类型？"><a href="#【Spring】你更倾向用那种事务管理类型？" class="headerlink" title="【Spring】你更倾向用那种事务管理类型？"></a>【Spring】<strong>你更倾向用那种事务管理类型？</strong></h3><p>大多数Spring框架的用户选择声明式事务管理，因为它对应用代码的影响最小，因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理，虽然比编程式事务管理（这种方式允许你通过代码控制事务）少了一点灵活性。</p>
<h3 id="【Spring】-解释AOP"><a href="#【Spring】-解释AOP" class="headerlink" title="【Spring】 解释AOP"></a>【Spring】 解释AOP</h3><p>面向切面的编程，或AOP， 是一种编程技术，允许程序模块化横向切割关注点，或横切典型的责任划分，如日志和事务管理。</p>
<h3 id="【Spring】Aspect-切面"><a href="#【Spring】Aspect-切面" class="headerlink" title="【Spring】Aspect 切面"></a>【Spring】<strong>Aspect 切面</strong></h3><p>AOP核心就是切面，它将多个类的通用行为封装成可重用的模块，该模块含有一组API提供横切功能。比如，一个日志模块可以被称作日志的AOP切面。根据需求的不同，一个应用程序可以有若干切面。在Spring AOP中，切面通过带有@Aspect注解的类实现。</p>
<h3 id="【Spring】在Spring-AOP-中，关注点和横切关注的区别是什么？"><a href="#【Spring】在Spring-AOP-中，关注点和横切关注的区别是什么？" class="headerlink" title="【Spring】在Spring AOP 中，关注点和横切关注的区别是什么？"></a>【Spring】<strong>在Spring AOP 中，关注点和横切关注的区别是什么？</strong></h3><p>关注点是应用中一个模块的行为，一个关注点可能会被定义成一个我们想实现的一个功能。</p>
<p>横切关注点是一个关注点，此关注点是整个应用都会使用的功能，并影响整个应用，比如日志，安全和数据传输，几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。</p>
<h3 id="【Spring】连接点"><a href="#【Spring】连接点" class="headerlink" title="【Spring】连接点"></a>【Spring】<strong>连接点</strong></h3><p>连接点代表一个应用程序的某个位置，在这个位置我们可以插入一个AOP切面，它实际上是个应用程序执行Spring AOP的位置。</p>
<h3 id="【Spring】通知"><a href="#【Spring】通知" class="headerlink" title="【Spring】通知"></a>【Spring】<strong>通知</strong></h3><p>通知是个在方法执行前或执行后要做的动作，实际上是程序执行时要通过SpringAOP框架触发的代码段。</p>
<p>Spring切面可以应用五种类型的通知：</p>
<p>before：前置通知，在一个方法执行前被调用</p>
<p>after：在方法执行之后调用的通知，无论方法执行是否成功</p>
<p>after-returning：仅当方法成功完成后执行的通知</p>
<p>after-throwing：在方法抛出异常退出时执行的通知</p>
<p>around：在方法执行之前和之后调用的通知</p>
<h3 id="【Spring】切点"><a href="#【Spring】切点" class="headerlink" title="【Spring】切点"></a>【Spring】<strong>切点</strong></h3><p>切入点是一个或一组连接点，通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。</p>
<h3 id="【Spring】什么是引入？"><a href="#【Spring】什么是引入？" class="headerlink" title="【Spring】什么是引入？"></a>【Spring】<strong>什么是引入？</strong></h3><p>引入允许我们在已存在的类中增加新的方法和属性。</p>
<h3 id="【Spring】什么是目标对象？"><a href="#【Spring】什么是目标对象？" class="headerlink" title="【Spring】什么是目标对象？"></a>【Spring】<strong>什么是目标对象？</strong></h3><p>被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知（advised）对象。</p>
<h3 id="【Spring】什么是代理？"><a href="#【Spring】什么是代理？" class="headerlink" title="【Spring】什么是代理？"></a>【Spring】<strong>什么是代理？</strong></h3><p>代理是通知目标对象后创建的对象。从客户端的角度看，代理对象和目标对象是一样的。</p>
<h3 id="【Spring】有几种不同类型的自动代理？"><a href="#【Spring】有几种不同类型的自动代理？" class="headerlink" title="【Spring】有几种不同类型的自动代理？"></a>【Spring】<strong>有几种不同类型的自动代理？</strong></h3><p>BeanNameAutoProxyCreator</p>
<p>DefaultAdvisorAutoProxyCreator</p>
<p>Metadata autoproxying</p>
<h3 id="【Spring】什么是织入。什么是织入应用的不同点？"><a href="#【Spring】什么是织入。什么是织入应用的不同点？" class="headerlink" title="【Spring】什么是织入。什么是织入应用的不同点？"></a>【Spring】<strong>什么是织入。什么是织入应用的不同点？</strong></h3><p>织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。</p>
<p>织入可以在编译时，加载时，或运行时完成。</p>
<h3 id="【Spring】解释基于XML-Schema方式的切面实现"><a href="#【Spring】解释基于XML-Schema方式的切面实现" class="headerlink" title="【Spring】解释基于XML Schema方式的切面实现"></a>【Spring】<strong>解释基于XML Schema方式的切面实现</strong></h3><p>在这种情况下，切面由常规类以及基于XML的配置实现。</p>
<h3 id="【Spring】解释基于注解的切面实现"><a href="#【Spring】解释基于注解的切面实现" class="headerlink" title="【Spring】解释基于注解的切面实现"></a>【Spring】<strong>解释基于注解的切面实现</strong></h3><p>在这种情况下(基于@AspectJ的实现)，涉及到的切面声明的风格与带有java5标注的普通java类一致。</p>
<h3 id="【Spring】什么是Spring的MVC框架？"><a href="#【Spring】什么是Spring的MVC框架？" class="headerlink" title="【Spring】什么是Spring的MVC框架？"></a>【Spring】<strong>什么是Spring的MVC框架？</strong></h3><p>Spring 配备构建Web 应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成，如Struts，Spring 的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。</p>
<h3 id="【Spring】DispatcherServlet"><a href="#【Spring】DispatcherServlet" class="headerlink" title="【Spring】DispatcherServlet"></a>【Spring】<strong>DispatcherServlet</strong></h3><p>Spring的MVC框架是围绕DispatcherServlet来设计的，它用来处理所有的HTTP请求和响应。</p>
<h3 id="【Spring】WebApplicationContext"><a href="#【Spring】WebApplicationContext" class="headerlink" title="【Spring】WebApplicationContext"></a>【Spring】<strong>WebApplicationContext</strong></h3><p>WebApplicationContext 继承了ApplicationContext  并增加了一些WEB应用必备的特有功能，它不同于一般的ApplicationContext ，因为它能处理主题，并找到被关联的servlet。</p>
<h3 id="【Spring】什么是Spring-MVC框架的控制器？"><a href="#【Spring】什么是Spring-MVC框架的控制器？" class="headerlink" title="【Spring】什么是Spring MVC框架的控制器？"></a>【Spring】<strong>什么是Spring MVC框架的控制器？</strong></h3><p>控制器提供一个访问应用程序的行为，此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个非常抽象的方式实现了一个控制层，允许用户创建多种用途的控制器。</p>
<h3 id="【Spring】-Controller-注解"><a href="#【Spring】-Controller-注解" class="headerlink" title="【Spring】@Controller 注解"></a>【Spring】<strong>@Controller 注解</strong></h3><p>该注解表明该类扮演控制器的角色，Spring不需要你继承任何其他控制器基类或引用Servlet API。</p>
<h3 id="【Spring】-RequestMapping-注解"><a href="#【Spring】-RequestMapping-注解" class="headerlink" title="【Spring】@RequestMapping 注解"></a>【Spring】<strong>@RequestMapping 注解</strong></h3><p>该注解是用来映射一个URL到一个类或一个特定的方处理法上。</p>

  	</div>
	  
	  <div class="article-tags tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
		
	
		<div class="art-item-footer">
				
					<span class="art-item-left"><i class="icon icon-chevron-thin-left"></i>prev：<a href="/2018/10/20/Java-面试题系列篇-Struts-框架/" rel="prev"  title="Java 面试题系列篇-struts 框架">
						Java 面试题系列篇-struts 框架 
					</a></span>
				
				
					<span class="art-item-right">next：<a href="/2018/10/20/Java-面试题系列篇-Mybatis-框架/" rel="next"  title="Java 面试题系列篇-Mybatis 框架">
						Java 面试题系列篇-Mybatis 框架
					</a><i class="icon icon-chevron-thin-right"></i></span>
				
		</div>
	
	</section>
	
</article>
<script>
	window.subData = {
		title: 'Java 面试题系列篇-Spring 框架',
		tools: true
	}
</script>

      </div>
      <aside class='l_side'>
        
  <section class='m_widget links'>
<div class='header'>Links</div>
<div class='content'>
    <ul class="entry">
    
        <li><a class="flat-box" target="_blank" href="https://iiong.com/">
            <div class='name'>淮城一只猫</div>
        </a></li>
    
    </ul>
</div>
</section>

  <section class='m_widget categories'>
<div class='header'>Categories</div>
<div class='content'>
    
    <ul class="entry">
    
        <li><a class="flat-box" href="/categories/Android基础/"><div class='name'>Android基础</div><div class='badget'>1</div></a></li>
    
    </ul>
    
</div>
</section>

  
<div class="m_widget tagcloud">
    <div class="header">Tags</div>
    <div class='content'>
        <a href="/tags/Android/" style="font-size: 14px; color: #808080">Android</a> <a href="/tags/HTML/" style="font-size: 14px; color: #808080">HTML</a> <a href="/tags/Java/" style="font-size: 20px; color: #000">Java</a> <a href="/tags/Python/" style="font-size: 14px; color: #808080">Python</a>
    </div>
</div>



      </aside>
      <script>setLoadingBarProgress(60);</script>
    </div>
  </div>
  <footer id="footer" class="clearfix">

	<div class="social-wrapper">
  	
      
        <a href="https://github.com/stkevintan" class="social github"
          target="_blank" rel="external">
          <span class="icon icon-github"></span>
        </a>
      
        <a href="https://twitter.com/kevinsfork" class="social twitter"
          target="_blank" rel="external">
          <span class="icon icon-twitter"></span>
        </a>
      
        <a href="/atom.xml" class="social rss"
          target="_blank" rel="external">
          <span class="icon icon-rss"></span>
        </a>
      
    
  </div>
  
  <div>Theme <a href='https://github.com/stkevintan/hexo-theme-material-flow' class="codename">MaterialFlow</a> designed by <a href="http://keyin.me/" target="_blank">Kevin Tan</a>.</div>
  
</footer>


  <script>setLoadingBarProgress(80);</script>
  

<script src="//apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src='//cdn.bootcss.com/node-waves/0.7.5/waves.min.js'></script>
<script src="//cdn.bootcss.com/scrollReveal.js/3.3.2/scrollreveal.min.js"></script>
<script src="/js/jquery.fitvids.js"></script>
<script>
	var GOOGLE_CUSTOM_SEARCH_API_KEY = "";
	var GOOGLE_CUSTOM_SEARCH_ENGINE_ID = "";
	var ALGOLIA_API_KEY = "";
	var ALGOLIA_APP_ID = "";
	var ALGOLIA_INDEX_NAME = "";
  var AZURE_SERVICE_NAME = "";
  var AZURE_INDEX_NAME = "";
  var AZURE_QUERY_KEY = "";
  var BAIDU_API_ID = "";
  var SEARCH_SERVICE = "hexo";
  var ROOT = "/"||"/";
  if(!ROOT.endsWith('/'))ROOT += '/';
</script>
<script src="/js/search.js"></script>
<script src="/js/app.js"></script>


  <script>setLoadingBarProgress(100);</script>
</body>
</html>
